Skip to content

Commit a14229e

Browse files
committed
Last stone weight
1 parent 46ec519 commit a14229e

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// 1046. Last stone weight
2+
// Topics: 'Array', 'Heap (Priority Queue)'
3+
4+
// You are given an array of integers stones where stones[i] is the weight of the ith stone.
5+
6+
// We are playing a game with the stones. On each turn, we choose the heaviest two stones and smash them together. Suppose the heaviest two stones have weights x and y with x <= y. The result of this smash is:
7+
8+
// If x == y, both stones are destroyed, and
9+
// If x != y, the stone of weight x is destroyed, and the stone of weight y has new weight y - x.
10+
11+
// At the end of the game, there is at most one stone left.
12+
13+
// Return the weight of the last remaining stone. If there are no stones left, return 0.
14+
15+
// Example 1:
16+
17+
// Input: stones = [2,7,4,1,8,1]
18+
// Output: 1
19+
// Explanation:
20+
// We combine 7 and 8 to get 1 so the array converts to [2,4,1,1,1] then,
21+
// we combine 2 and 4 to get 2 so the array converts to [2,1,1,1] then,
22+
// we combine 2 and 1 to get 1 so the array converts to [1,1,1] then,
23+
// we combine 1 and 1 to get 0 so the array converts to [1] then that's the value of the last stone.
24+
25+
// Example 2:
26+
27+
// Input: stones = [1]
28+
// Output: 1
29+
30+
// Constraints:
31+
32+
// 1 <= stones.length <= 30
33+
// 1 <= stones[i] <= 1000
34+
35+
package laststoneweight
36+
37+
func lastStoneWeight(stones []int) int {
38+
heap := newMaxHeap(stones)
39+
40+
for len(heap.stones) >= 2 {
41+
biggest1, biggest2 := heap.pop(), heap.pop()
42+
if biggest1 == biggest2 {
43+
continue
44+
}
45+
heap.push(biggest1 - biggest2)
46+
}
47+
if len(heap.stones) == 0 {
48+
return 0
49+
}
50+
return heap.stones[0]
51+
}
52+
53+
type maxheap struct {
54+
stones []int
55+
}
56+
57+
func newMaxHeap(stones []int) *maxheap {
58+
heap := &maxheap{stones: stones}
59+
i := (len(heap.stones) - 1) / 2
60+
for i >= 0 {
61+
heap.percolate(i)
62+
i--
63+
}
64+
return heap
65+
}
66+
67+
func (m *maxheap) push(stone int) {
68+
m.stones = append(m.stones, stone)
69+
i := len(m.stones) - 1
70+
for i > 0 && m.stones[i] > m.stones[(i-1)/2] {
71+
m.stones[i], m.stones[(i-1)/2] = m.stones[(i-1)/2], m.stones[i]
72+
i = (i - 1) / 2
73+
}
74+
}
75+
76+
func (m *maxheap) pop() int {
77+
if len(m.stones) == 0 {
78+
return -1
79+
}
80+
if len(m.stones) == 1 {
81+
v := m.stones[0]
82+
m.stones = []int{}
83+
return v
84+
}
85+
v := m.stones[0]
86+
m.stones[0] = m.stones[len(m.stones)-1]
87+
m.stones = m.stones[:len(m.stones)-1]
88+
m.percolate(0)
89+
return v
90+
}
91+
92+
func (m *maxheap) percolate(i int) {
93+
for {
94+
largest := i
95+
left := 2*i + 1
96+
right := 2*i + 2
97+
if left < len(m.stones) && m.stones[left] > m.stones[largest] {
98+
largest = left
99+
}
100+
if right < len(m.stones) && m.stones[right] > m.stones[largest] {
101+
largest = right
102+
}
103+
104+
if largest != i {
105+
m.stones[largest], m.stones[i] = m.stones[i], m.stones[largest]
106+
i = largest
107+
} else {
108+
break
109+
}
110+
}
111+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package laststoneweight
2+
3+
import "testing"
4+
5+
func TestLastStoneWeight(t *testing.T) {
6+
tests := []struct {
7+
name string
8+
stones []int
9+
want int
10+
}{
11+
{
12+
name: "example 1",
13+
stones: []int{2, 7, 4, 1, 8, 1},
14+
want: 1,
15+
},
16+
{
17+
name: "example 2",
18+
stones: []int{1},
19+
want: 1,
20+
},
21+
{
22+
name: "all stones destroyed",
23+
stones: []int{2, 2},
24+
want: 0,
25+
},
26+
{
27+
name: "two different stones",
28+
stones: []int{3, 7},
29+
want: 4,
30+
},
31+
{
32+
name: "multiple same weight stones",
33+
stones: []int{5, 5, 5, 5},
34+
want: 0,
35+
},
36+
{
37+
name: "descending order",
38+
stones: []int{9, 7, 5, 3, 1},
39+
want: 1,
40+
},
41+
{
42+
name: "ascending order",
43+
stones: []int{1, 3, 5, 7, 9},
44+
want: 1,
45+
},
46+
{
47+
name: "three stones",
48+
stones: []int{2, 7, 4},
49+
want: 1,
50+
},
51+
}
52+
53+
for _, tt := range tests {
54+
t.Run(tt.name, func(t *testing.T) {
55+
got := lastStoneWeight(tt.stones)
56+
if got != tt.want {
57+
t.Errorf("lastStoneWeight(%v) = %v, want %v", tt.stones, got, tt.want)
58+
}
59+
})
60+
}
61+
}

0 commit comments

Comments
 (0)