A clear explanation of simulating stone smashing to find the last remaining weight using a max heap.
Problem Restatement
We have a collection of stones, each with a positive weight.
In each round, we smash the two heaviest stones together:
- If equal: both are destroyed.
- If not equal: the lighter is destroyed and the heavier remains with weight
heavier - lighter.
We repeat until at most one stone is left.
Return the weight of the last stone, or 0 if none remain.
The official constraints state that 1 <= stones.length <= 30 and 1 <= stones[i] <= 1000.
Input and Output
| Item | Meaning |
|---|---|
| Input | Array stones |
| Output | Weight of last stone, or 0 |
Function shape:
def lastStoneWeight(stones: list[int]) -> int:
...Examples
Example 1:
stones = [2, 7, 4, 1, 8, 1]Smash 8 and 7 → 1. Stones: [2, 4, 1, 1, 1].
Smash 4 and 2 → 2. Stones: [2, 1, 1, 1].
Smash 2 and 1 → 1. Stones: [1, 1, 1].
Smash 1 and 1 → 0. Stones: [1].
Answer:
1Key Insight
We always need the two largest stones. A max heap gives O(log n) access to the largest element.
Python’s heapq is a min-heap, so negate all values to simulate a max heap.
Algorithm
- Push all negated stone weights onto a min heap.
- While the heap has more than one element:
- Pop two largest weights.
- If not equal, push back the difference (negated).
- Return the remaining weight, or
0if heap is empty.
Edge Cases
- Check the minimum input size allowed by the constraints.
- Verify duplicate values or tie cases if the input can contain them.
- Keep the return value aligned with the exact failure case in the statement.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(n log n) | At most n smash operations, each O(log n) |
| Space | O(n) | Heap storage |
Common Pitfalls
- Do not optimize away the invariant; the code should still make it clear what condition is being maintained.
- Prefer problem-specific names over one-letter variables once the logic becomes stateful.
Implementation
import heapq
class Solution:
def lastStoneWeight(self, stones: list[int]) -> int:
heap = [-s for s in stones]
heapq.heapify(heap)
while len(heap) > 1:
a = -heapq.heappop(heap)
b = -heapq.heappop(heap)
if a != b:
heapq.heappush(heap, -(a - b))
return -heap[0] if heap else 0Testing
def run_tests():
s = Solution()
assert s.lastStoneWeight([2, 7, 4, 1, 8, 1]) == 1
assert s.lastStoneWeight([1]) == 1
assert s.lastStoneWeight([2, 2]) == 0
assert s.lastStoneWeight([3, 7, 2]) == 2
print("all tests passed")
run_tests()| Test | Expected | Why |
|---|---|---|
| Standard example | 1 | Simulation result |
| Single stone | 1 | Nothing to smash |
| Equal stones | 0 | Both destroyed |
| Three stones | 2 | 7-3=4, 4-2=2 |