Last Stone Weight - Complete Solution Guide
Last Stone Weight is LeetCode problem 1046, a Easy level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
You are given an array of integers stones where stones[i] is the weight of the i th stone. We are playing a game with the stones. On each turn, we choose the heaviest two stones and smash them together. Suppose the heaviest two stones have weights x and y with x <= y . The result of this smash is: If x == y , both stones are destroyed, and If x != y , the stone of weight x is destroyed, and the stone of weight y has new weight y - x . At the end of the game, there is at most one stone left. Retu
Detailed Explanation
Imagine you're playing a peculiar game where you have a pile of stones, each with a specific weight. Your goal is to keep smashing them together until you're left with at most one stone. The rules for smashing are quite specific: in each turn, you *must* pick the two heaviest stones currently available. Let's call their weights 'x' and 'y', making sure 'x' is always less than or equal to 'y'. What happens after the smash? If 'x' and 'y' are identical, both stones vanish into dust. If they are different, the lighter stone ('x') is destroyed, but the heavier stone ('y') survives, albeit with a new, reduced weight of 'y - x'. This new stone is then thrown back into the pile. The game continues this cycle – pick two heaviest, smash, potentially add a new one – until there are either zero or one stone left. Your task is to report the weight of that final stone, or 0 if all stones were destroyed. The interesting aspect here is the dynamic nature: stones are removed, and a new stone might be added with a different weight. This isn't a simple one-time operation but a sequence of choices where each choice (the two heaviest stones) depends on the previous outcomes. You can't just pick any two; it has to be the largest, which means the set of available stones is constantly changing in a way that necessitates efficient access to the maximum values.
Solution Approach
The core challenge is consistently identifying the 'heaviest two stones' from a constantly changing collection. This screams for a priority queue, specifically one that can give us the maximum elements. Python's `heapq` module implements a *min-heap*. To efficiently get the two largest positive weights, the solution employs a clever trick: it stores the *negative* of all stone weights in the heap. When you extract the smallest (most negative) elements from this modified min-heap, you are effectively getting the largest (most positive) original stone weights. The algorithm initializes the heap by converting all stone weights to their negatives and then heapifying the list. It then enters a loop that continues as long as there are at least two stones available to smash. In each iteration, it extracts the two smallest (most negative) elements, negates them back to their true positive values (`y` and `x`), and simulates the smash. If `x` and `y` are different, the resulting `y - x` stone is created, and its *negative* weight is pushed back into the heap. If `x` and `y` are the same, nothing is pushed back, correctly simulating both stones being destroyed. Finally, once the loop finishes, if any stone remains (meaning the heap is not empty), its original positive weight is returned; otherwise, 0 is returned.
Step-by-Step Algorithm
- Step 1: Create a priority queue (max-heap).
- Step 2: Add all the stone weights to the priority queue.
- Step 3: While the priority queue contains more than one element:
- Step 4: Remove the two largest stones (x and y, with y >= x).
- Step 5: If x != y, add (y - x) back to the priority queue.
- Step 6: If the priority queue is empty, return 0; otherwise, return the weight of the remaining stone.
Key Insights
- Leveraging Python's `heapq` as a Max-Heap: Since `heapq` is a min-heap, transforming all stone weights to their negative counterparts allows `heapq.heappop` to consistently retrieve the largest original stone weight. This is a crucial adaptation for problems requiring maximum elements from a heap in Python, avoiding the need for a custom max-heap implementation.
- The 'Heaviest Two' Implies a Priority Queue: The problem's core operation of repeatedly selecting the two heaviest stones strongly points towards using a priority queue (heap). It efficiently provides the largest elements (in `O(log N)` time per extraction) without needing to sort the entire collection repeatedly, which would be far less efficient for a dynamic set.
- Dynamic Stone Population Management: The solution elegantly handles the changing number of stones within the `while len(stones) > 1` loop. Each iteration correctly reduces the stone count by one (two removed, one potentially added) or two (both destroyed). The loop naturally concludes when zero or one stone remains, directly mapping to the problem's termination conditions and final result.
Complexity Analysis
Time Complexity: O(nlogn)
Space Complexity: O(n)
Topics
This problem involves: Array, Heap (Priority Queue).
Companies
Asked at: Flipkart, Nvidia, PayPal, Rippling.