Repeatedly smash the two heaviest stones together — if they differ, the lighter one is destroyed and the difference survives. A max-heap always gives you the two heaviest in O(log n) time, making the whole simulation O(n log n).
You have a pile of stones with weights. Each turn, pick the two heaviest — y ≥ x. If y === x both are destroyed; otherwise the stone of weight y − x remains. Repeat until at most one stone is left and return its weight (or 0 if empty). Example: [2, 7, 4, 1, 8, 1] → smash 8+7 → 1 left → pile is [2, 4, 1, 1, 1] → smash 4+2 → 2 left → [2, 1, 1, 1] → smash 2+1 → 1 → [1, 1, 1] → smash 1+1 → 0 → [1] → answer is 1.
O(log n) and push back the remainder in O(log n). That is the entire algorithm — the heap does all the work.O(n) with bottom-up heapify, or O(n log n) with repeated pushes — either is fine here.y and x (y ≥ x). Each pop is O(log n).y !== x, push y − x back. The difference is always positive and smaller than y, so it will not be the next maximum unless everything else is smaller.heap[0] or 0.heap.length > 1 in the loop condition and instead check heap.length > 0. That causes an extra iteration where you pop one stone and then try to pop a second from an empty heap — a crash or an incorrect extra call. You need two stones to smash, so loop only while at least two remain.The heap holds at most n elements → O(n) extra space. There is no known in-place variant that preserves the same time complexity.
[2, 7, 4, 1, 8, 1]. Max is 8. Begin smashing.1▶function lastStoneWeight(stones: number[]): number {2 // Max-heap (simulated with a max-first comparator via a custom MinHeap inverted).3 // Here we implement a simple binary max-heap inline for clarity.4▶ const heap: number[] = [];56 function push(val: number): void {7 heap.push(val);8 let i = heap.length - 1;9 while (i > 0) {10 const p = (i - 1) >> 1;11 if (heap[p] >= heap[i]) break;12 [heap[p], heap[i]] = [heap[i], heap[p]];13 i = p;14 }15 }1617 function pop(): number {18 const top = heap[0];19 const last = heap.pop()!;20 if (heap.length > 0) {21 heap[0] = last;22 let i = 0;23 while (true) {24 const l = 2 * i + 1, r = 2 * i + 2;25 let max = i;26 if (l < heap.length && heap[l] > heap[max]) max = l;27 if (r < heap.length && heap[r] > heap[max]) max = r;28 if (max === i) break;29 [heap[i], heap[max]] = [heap[max], heap[i]];30 i = max;31 }32 }33 return top;34 }3536▶ for (const s of stones) push(s);3738 while (heap.length > 1) {39 const y = pop(); // heaviest40 const x = pop(); // second heaviest41 if (y !== x) push(y - x); // leftover fragment42 }4344 return heap.length === 0 ? 0 : heap[0];45}
function lastStoneWeight(stones: number[]): number {
// Max-heap (simulated with a max-first comparator via a custom MinHeap inverted).
// Here we implement a simple binary max-heap inline for clarity.
const heap: number[] = [];
function push(val: number): void {
heap.push(val);
let i = heap.length - 1;
while (i > 0) {
const p = (i - 1) >> 1;
if (heap[p] >= heap[i]) break;
[heap[p], heap[i]] = [heap[i], heap[p]];
i = p;
}
}
function pop(): number {
const top = heap[0];
const last = heap.pop()!;
if (heap.length > 0) {
heap[0] = last;
let i = 0;
while (true) {
const l = 2 * i + 1, r = 2 * i + 2;
let max = i;
if (l < heap.length && heap[l] > heap[max]) max = l;
if (r < heap.length && heap[r] > heap[max]) max = r;
if (max === i) break;
[heap[i], heap[max]] = [heap[max], heap[i]];
i = max;
}
}
return top;
}
for (const s of stones) push(s);
while (heap.length > 1) {
const y = pop(); // heaviest
const x = pop(); // second heaviest
if (y !== x) push(y - x); // leftover fragment
}
return heap.length === 0 ? 0 : heap[0];
}push appends and sifts up; pop swaps the root with the last element, removes it, then sifts the new root down. Both run in O(log n).n stones one-by-one takes O(n log n). A bottom-up heapify pass would do it in O(n), but for this problem size the difference is negligible.y ≥ x). If y !== x the fragment y − x is pushed back. The loop guard heap.length > 1 is critical — we need two stones to compare.0 accordingly.O(n log n) time: up to n − 1 rounds, each with 2 pops and 1 push at O(log n). O(n) space for the heap array.y − x result in an array alongside its round number.x − y if nonzero — mirrors this solution exactly.O(log n) per operation. Sorted array + binary search insert is O(n) per round — worse for large inputs.O(n log n) per round → O(n² log n) total, vs O(n log n) with a heap.stones = [5]) → return 5; all equal ([3, 3, 3, 3]) → all pairs cancel → return 0 or 3 depending on count parity.function lastStoneWeight(stones: number[]): number {
// Max-heap (simulated with a max-first comparator via a custom MinHeap inverted).
// Here we implement a simple binary max-heap inline for clarity.
const heap: number[] = [];
function push(val: number): void {
heap.push(val);
let i = heap.length - 1;
while (i > 0) {
const p = (i - 1) >> 1;
if (heap[p] >= heap[i]) break;
[heap[p], heap[i]] = [heap[i], heap[p]];
i = p;
}
}
function pop(): number {
const top = heap[0];
const last = heap.pop()!;
if (heap.length > 0) {
heap[0] = last;
let i = 0;
while (true) {
const l = 2 * i + 1, r = 2 * i + 2;
let max = i;
if (l < heap.length && heap[l] > heap[max]) max = l;
if (r < heap.length && heap[r] > heap[max]) max = r;
if (max === i) break;
[heap[i], heap[max]] = [heap[max], heap[i]];
i = max;
}
}
return top;
}
for (const s of stones) push(s);
while (heap.length > 1) {
const y = pop(); // heaviest
const x = pop(); // second heaviest
if (y !== x) push(y - x); // leftover fragment
}
return heap.length === 0 ? 0 : heap[0];
}O(n log n) time: up to n − 1 rounds, each with 2 pops and 1 push at O(log n). O(n) space for the heap array.Each turn, sort the stones, take the two heaviest off the end, smash them, and push back any leftover — repeating until at most one stone remains.
function lastStoneWeight(stones: number[]): number {
// Mutate the array in place; sort fresh every round to find the two heaviest.
while (stones.length > 1) {
stones.sort((a, b) => a - b);
const y = stones.pop()!; // heaviest
const x = stones.pop()!; // second heaviest
if (y !== x) stones.push(y - x); // leftover fragment
}
return stones.length === 0 ? 0 : stones[0];
}n rounds, each doing an O(n log n) sort, gives O(n² log n). A max-heap turns each round into two O(log n) pops and one push, for O(n log n) overall.| "repeatedly pick the two largest/smallest" | max- or min-heap |
| pile shrinks each round, need running maximum | max-heap pop ×2, push diff |
| stream of values, need k-th largest at any time | min-heap of size k |
| merge or combine elements greedily by weight | priority queue simulation |
const heap: number[] = [];
// push / pop helpers (max-heap)
for (const s of stones) push(s);
while (heap.length > 1) {
const y = pop(); // heaviest
const x = pop(); // second heaviest
if (y !== x) push(y - x);
}
return heap.length === 0 ? 0 : heap[0];O(n log n) per iteration → O(n² log n) total. A heap gives O(log n) pop/push, so the whole simulation is O(n log n).[2, 7, 4, 1, 8, 1], what is the correct output?heap.length > 1 and NOT heap.length > 0?[10, 10]: what happens?