Last Stone Weight
Easy · Heap / Priority Queue · Explanation and code example
Bucket Sort
How it works
Since all stone values lie within a limited numeric range, we can avoid sorting or using a heap by using bucket sort / frequency counting.
Instead of tracking every stone individually, we store how many stones exist for each possible weight.
Key ideas:
- Let
bucket[w]store how many stones of weightwwe have. - We repeatedly look for the heaviest available stone.
- When smashing stones of weights
aandb:- If
a == b, they cancel out. - If different, the leftover stone
a - bgets added back into the bucket.
- If
- We continue until only one non-zero weight remains.
This works because bucket operations (increment, decrement, scanning) are efficient when the weight range is manageable.
Steps
- Find the maximum stone weight.
- Create a frequency array
bucketof sizemaxWeight + 1. - Count how many stones of each weight exist.
- Start from the heaviest weight and repeat:
- If the count at this weight is even, all stones cancel in pairs.
- If odd, one stone remains; find the next heaviest stone to smash with it.
- Compute the difference and update the bucket.
- Move the pointer to the next heaviest relevant weight.
- When only one weight remains with an odd count, return it.
- If all stones cancel out, return
0.
Complexity
- Time complexity:
O(n + w) - Space complexity:
O(w)
Where
nis the length of thestonesarray andwis the maximum value in thestonesarray.
Things to watch for
Using a Min-Heap Instead of Max-Heap
Many languages provide min-heaps by default (like Python's heapq). You need to either use a max-heap or negate the values when inserting and extracting. Forgetting this results in smashing the two smallest stones instead of the two heaviest.
Forgetting to Handle the Empty Result Case
After all smashing is complete, the stones array could be empty (all stones canceled out). Returning stones[0] without checking if the array is empty causes an index error. Always check if the result is empty and return 0 in that case.
Python code example
from typing import List
class Solution:
def lastStoneWeight(self, stones: List[int]) -> int:
maxStone = max(stones)
bucket = [0] * (maxStone + 1)
for stone in stones:
bucket[stone] += 1
first = second = maxStone
while first > 0:
if bucket[first] % 2 == 0:
first -= 1
continue
j = min(first - 1, second)
while j > 0 and bucket[j] == 0:
j -= 1
if j == 0:
return first
second = j
bucket[first] -= 1
bucket[second] -= 1
bucket[first - second] += 1
first = max(first - second, second)
return first
C++ code example
class Solution {
public:
int lastStoneWeight(vector<int>& stones) {
int maxStone = 0;
for (int stone : stones) {
maxStone = max(maxStone, stone);
}
vector<int> bucket(maxStone + 1, 0);
for (int stone : stones) {
bucket[stone]++;
}
int first = maxStone, second = maxStone;
while (first > 0) {
if (bucket[first] % 2 == 0) {
first--;
continue;
}
int j = min(first - 1, second);
while (j > 0 && bucket[j] == 0) {
j--;
}
if (j == 0) {
return first;
}
second = j;
bucket[first]--;
bucket[second]--;
bucket[first - second]++;
first = max(first - second, second);
}
return first;
}
};
Source and license
Adapted from NeetCode’s source · MIT license. Node types are supplied by LeetCode where needed.