Last Stone Weight
A max-heap gives the heaviest stone in O(log N). Pop the two heaviest. If they differ, push back their difference. The pile is never sorted as a whole.
The top of the max-heap is always the heaviest remaining stone, so the two pops are always the two stones the rule asks for. The heap re-orders itself after every push and pop, so this stays true for the whole game.
Problem
You have a pile of stones. Stone i weighs stones[i].
Repeat this while two or more stones are left:
- Take the two heaviest stones. Call the heavier one
yand the lighter onex. - If
x == y, both stones are destroyed. - If
x != y, the lighter stone is destroyed and the heavier one now weighsy − x.
When one stone is left, return its weight. If no stones are left, return 0.
stones, a list of stone weights.
The weight of the last stone, or 0 if none is left.
7 and 8 → 1, so the pile is [2, 4, 1, 1, 1]. Then 4 and 2 → 2, pile [2, 1, 1, 1]. Then 2 and 1 → 1, pile [1, 1, 1]. Then 1 and 1 are equal, so both are destroyed. One stone (weight 1) is left.
There is only one stone, so it is the last one.
- • 1 ≤ stones.length ≤ 30
- • 1 ≤ stones[i] ≤ 1000
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
Each turn I need the two heaviest stones. Which data structure gives me the largest item quickly?
- 2.
After a smash, the new stone can land anywhere in the weight order. Does that break a list I already sorted?
- 3.
Each turn removes two stones and adds at most one. How many turns can happen at most?
- 4.
What should the answer be when every stone is destroyed?
- 5.
If I sort the pile once, what must I do after each smash to keep it correct?
Brute force approach
Better approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Sort the pile each turn and smash the two heaviest at the back | O(N² log N) | O(1) |
| Better | Sort once; after each smash, insert the new stone at its sorted spot | O(N²) | O(1) |
| Optimal | Keep the stones in a max-heap; pop the two heaviest, push the difference | O(N log N) | O(N) |
Why does this belong to this pattern?
- “the two heaviest stones”We need the current maximum, twice per turn. The maximum changes after every turn, so the structure must update fast.
- “a new stone of weight y − x”The pile changes by one insert per turn. A heap takes one insert in O(log n) without re-sorting.
- “until one stone is left”Keep looping on the size of the pile, not on a fixed count.
This is the anchor of the Kth element sub-pattern. The heap holds the whole pile, not just K items, because the pile keeps changing after each turn. The next questions keep only K items in a heap, which is where the size limit of K comes in.
Don't make this mistake
greater<int> puts the lightest stone on top, so each turn smashes the two lightest stones. On the dry-run [2, 7, 4, 1, 8, 1] the min-heap pops 1 and 1 first (equal, both gone), then 2 and 4 (push 2), then 2 and 7 (push 5), then 5 and 8 (push 3). It returns 3. The correct answer is 1.
The input [2, 2] destroys both stones, so the heap is empty when the loop ends. top() on an empty priority_queue is undefined behaviour, usually a crash. The answer should be 0.
On the dry-run, after 8 and 7 are smashed, the pile is [1, 1, 2, 4, 1] because the new 1 was put at the end. The last two are then 1 and 4, but the real two heaviest are 4 and 2. The list is no longer sorted, so the wrong pair gets smashed.
Want to implement this?
Write it yourself on LeetCode, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like Heap — Top K translate into production architectures and low-level memory mechanics.