Last Stone Weight Solution
Smash the two heaviest stones together repeatedly. If they differ, the remainder stays. Return the weight of the last remaining stone, or 0 if none.
Problem Statement
You have a collection of stones with positive integer weights. Each turn, pick the two heaviest stones and smash them. If they're equal, both are destroyed. If not, the lighter one is destroyed and the heavier one's weight is reduced by the lighter's weight. Return the weight of the last stone, or 0 if no stones remain.
Brute Force โ Sort Every Turn O(nยฒ log n)
Sort the array each turn, take the last two elements (heaviest), smash them, and insert the remainder back. Repeat until one or zero stones remain.
Sorting always places the two heaviest at the end. Correct by simulation โ we follow the problem's exact rules each round.
| Metric | Value |
|---|---|
| Time | O(nยฒ log n) โ sort O(n log n) per round ร n rounds |
| Space | O(n) |
Max-Heap โ O(n log n)
A max-heap always gives you the largest element in O(1) and extracts it in O(log n). Each round: pop the two largest, smash them, and push back the remainder if any. Repeat until โค 1 stone.
- Step 1: Insert all stones into a max-heap.
- Step 2: While heap has โฅ 2 elements: poll the two largest.
- Step 3: If they differ, push
first - secondback. - Step 4: Return heap.peek() if one element remains, else 0.
- Any simulation that repeatedly needs the maximum (or minimum) element from a dynamic collection โ think heap.
- The signal is "pick the best available, modify, put it back." This pattern appears in LC 1046 (Last Stone Weight), LC 621 (Task Scheduler), LC 767 (Reorganize String), and merge-k-sorted problems.
- Java's
PriorityQueueis a min-heap by default. - For a max-heap, use
new PriorityQueue<>(Collections.reverseOrder()). - In Python, negate values: push
-stoneand pop gives the most-negative (i.e., largest original).
Visual Walkthrough
Trace through stones = [2, 7, 4, 1, 8, 1]:
Code โ Java & Python
Complexity Analysis
| Approach | Time | Space | Trade-off |
|---|---|---|---|
| Sort every round | O(nยฒ log n) | O(n) | Simple but redundant re-sorting |
| Sorted insert (bisect) | O(nยฒ) | O(n) | O(log n) find + O(n) shift per round |
| Max-Heap โ optimal | O(n log n) | O(n) | O(log n) per poll/offer ร n rounds |
- Inserting into a sorted array is O(n) due to shifting elements. A heap gives O(log n) per insertion and extraction.
- For n=30 the difference is negligible, but the heap solution is the standard pattern for interviews.
Edge Cases & Pitfalls
| Case | Input | Why It Matters |
|---|---|---|
| Single stone | [5] | No smashing needed โ return 5. |
| Two equal stones | [3, 3] | Both destroyed โ heap empty โ return 0. |
| All same weight | [2, 2, 2, 2] | Pair-wise destruction โ return 0 (even count) or one stone (odd). |
| Already sorted ascending | [1, 2, 3] | Heap reorders to [3, 2, 1]. Smash 3-2=1, then 1-1=0 โ return 0. |
| Large difference | [1000, 1] | 999 survives. One round, one stone remains. |
| All ones | [1, 1, 1] | Smash 1,1โ0. One stone (1) remains. |
first - second, you must push -(first - second) to maintain the max-heap invariant. Pushing the positive difference treats it as a small number in the min-heap, corrupting the order.