Last Stone Weight II
MediumUpdated: Aug 2, 2025
Practice on:
Problem
You are given an array of integers stones where stones[i] is the weight of the ith stone.
We are playing a game with the stones. On each turn, we choose any two stones and smash them together. Suppose the 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 weightxis destroyed, and the stone of weightyhas new weighty - x.
At the end of the game, there is at most one stone left.
Return the smallest possible weight of the left stone. If there are no stones left, return 0.
Examples
Example 1
Input: stones = [2,7,4,1,8,1]
Output: 1
Explanation:
We can combine 2 and 4 to get 2, so the array converts to [2,7,1,8,1] then,
we can combine 7 and 8 to get 1, so the array converts to [2,1,1,1] then,
we can combine 2 and 1 to get 1, so the array converts to [1,1,1] then,
we can combine 1 and 1 to get 0, so the array converts to [1], then that's the optimal value.
Example 2
Input: stones = [31,26,33,21,40]
Output: 5
Constraints
1 <= stones.length <= 301 <= stones[i] <= 100
Solution
Method 1 – Subset Sum Dynamic Programming
Intuition
The problem can be transformed into partitioning the stones into two groups such that the difference of their sums is minimized. This is a classic subset sum problem, similar to partitioning an array into two subsets with the minimum difference.
Approach
- Compute the total sum of all stones.
- Use dynamic programming to find the largest possible sum not exceeding half of the total sum that can be formed by a subset of stones.
- The answer is the difference between the total sum and twice this largest possible subset sum.
Code
C++
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum = accumulate(stones.begin(), stones.end(), 0);
int target = sum / 2;
vector<bool> dp(target + 1, false);
dp[0] = true;
for (int s : stones) {
for (int j = target; j >= s; --j) {
dp[j] = dp[j] || dp[j - s];
}
}
for (int j = target; j >= 0; --j) {
if (dp[j]) return sum - 2 * j;
}
return 0;
}
};
Go
func lastStoneWeightII(stones []int) int {
sum := 0
for _, s := range stones {
sum += s
}
target := sum / 2
dp := make([]bool, target+1)
dp[0] = true
for _, s := range stones {
for j := target; j >= s; j-- {
dp[j] = dp[j] || dp[j-s]
}
}
for j := target; j >= 0; j-- {
if dp[j] {
return sum - 2*j
}
}
return 0
}
Java
class Solution {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int s : stones) sum += s;
int target = sum / 2;
boolean[] dp = new boolean[target + 1];
dp[0] = true;
for (int s : stones) {
for (int j = target; j >= s; --j) {
dp[j] = dp[j] || dp[j - s];
}
}
for (int j = target; j >= 0; --j) {
if (dp[j]) return sum - 2 * j;
}
return 0;
}
}
Kotlin
class Solution {
fun lastStoneWeightII(stones: IntArray): Int {
val sum = stones.sum()
val target = sum / 2
val dp = BooleanArray(target + 1)
dp[0] = true
for (s in stones) {
for (j in target downTo s) {
dp[j] = dp[j] || dp[j - s]
}
}
for (j in target downTo 0) {
if (dp[j]) return sum - 2 * j
}
return 0
}
}
Python
class Solution:
def lastStoneWeightII(self, stones: list[int]) -> int:
total = sum(stones)
target = total // 2
dp = [False] * (target + 1)
dp[0] = True
for s in stones:
for j in range(target, s - 1, -1):
dp[j] = dp[j] or dp[j - s]
for j in range(target, -1, -1):
if dp[j]:
return total - 2 * j
return 0
Rust
impl Solution {
pub fn last_stone_weight_ii(stones: Vec<i32>) -> i32 {
let sum: i32 = stones.iter().sum();
let target = sum / 2;
let mut dp = vec![false; (target + 1) as usize];
dp[0] = true;
for &s in &stones {
for j in (s..=target).rev() {
dp[j as usize] = dp[j as usize] || dp[(j - s) as usize];
}
}
for j in (0..=target).rev() {
if dp[j as usize] {
return sum - 2 * j;
}
}
0
}
}
TypeScript
class Solution {
lastStoneWeightII(stones: number[]): number {
const sum = stones.reduce((a, b) => a + b, 0);
const target = Math.floor(sum / 2);
const dp = Array(target + 1).fill(false);
dp[0] = true;
for (const s of stones) {
for (let j = target; j >= s; --j) {
dp[j] = dp[j] || dp[j - s];
}
}
for (let j = target; j >= 0; --j) {
if (dp[j]) return sum - 2 * j;
}
return 0;
}
}
Complexity
- ⏰ Time complexity:
O(n * sum/2), wherenis the number of stones andsumis the total weight. Each stone and each possible sum up to half the total are considered. - 🧺 Space complexity:
O(sum/2), for the DP array.