--- comments: true difficulty: 中等 edit_url: https://github.com/doocs/leetcode/edit/main/solution/1000-1099/1049.Last%20Stone%20Weight%20II/README.md rating: 2092 source: 第 137 场周赛 Q4 tags: - 数组 - 动态规划 --- # [1049. 最后一块石头的重量 II](https://leetcode.cn/problems/last-stone-weight-ii) [English Version](/solution/1000-1099/1049.Last%20Stone%20Weight%20II/README_EN.md) ## 题目描述

有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0

 

示例 1:

输入:stones = [2,7,4,1,8,1]
输出:1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。

示例 2:

输入:stones = [31,26,33,21,40]
输出:5

 

提示:

## 解法 ### 方法一:动态规划 **两个**石头的重量越接近,粉碎后的新重量就越小。同样的,**两堆**石头的重量越接近,它们粉碎后的新重量也越小。 所以本题可以转换为,计算容量为 `sum / 2` 的背包最多能装多少重量的石头。 定义 `dp[i][j]` 表示从前 i 个石头中选出若干个,使得所选石头重量之和为不超过 j 的最大重量。 #### Python3 ```python class Solution: def lastStoneWeightII(self, stones: List[int]) -> int: s = sum(stones) m, n = len(stones), s >> 1 dp = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(n + 1): dp[i][j] = dp[i - 1][j] if stones[i - 1] <= j: dp[i][j] = max( dp[i][j], dp[i - 1][j - stones[i - 1]] + stones[i - 1] ) return s - 2 * dp[-1][-1] ``` #### Java ```java class Solution { public int lastStoneWeightII(int[] stones) { int s = 0; for (int v : stones) { s += v; } int m = stones.length; int n = s >> 1; int[][] dp = new int[m + 1][n + 1]; for (int i = 1; i <= m; ++i) { for (int j = 0; j <= n; ++j) { dp[i][j] = dp[i - 1][j]; if (stones[i - 1] <= j) { dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - stones[i - 1]] + stones[i - 1]); } } } return s - dp[m][n] * 2; } } ``` #### C++ ```cpp class Solution { public: int lastStoneWeightII(vector& stones) { int s = accumulate(stones.begin(), stones.end(), 0); int m = stones.size(), n = s >> 1; vector> dp(m + 1, vector(n + 1)); for (int i = 1; i <= m; ++i) { for (int j = 0; j <= n; ++j) { dp[i][j] = dp[i - 1][j]; if (stones[i - 1] <= j) dp[i][j] = max(dp[i][j], dp[i - 1][j - stones[i - 1]] + stones[i - 1]); } } return s - dp[m][n] * 2; } }; ``` #### Go ```go func lastStoneWeightII(stones []int) int { s := 0 for _, v := range stones { s += v } m, n := len(stones), s>>1 dp := make([][]int, m+1) for i := range dp { dp[i] = make([]int, n+1) } for i := 1; i <= m; i++ { for j := 0; j <= n; j++ { dp[i][j] = dp[i-1][j] if stones[i-1] <= j { dp[i][j] = max(dp[i][j], dp[i-1][j-stones[i-1]]+stones[i-1]) } } } return s - dp[m][n]*2 } ``` #### Rust ```rust impl Solution { #[allow(dead_code)] pub fn last_stone_weight_ii(stones: Vec) -> i32 { let n = stones.len(); let mut sum = 0; for e in &stones { sum += *e; } let m = (sum / 2) as usize; let mut dp: Vec> = vec![vec![0; m + 1]; n + 1]; // Begin the actual dp process for i in 1..=n { for j in 1..=m { dp[i][j] = if stones[i - 1] > (j as i32) { dp[i - 1][j] } else { std::cmp::max( dp[i - 1][j], dp[i - 1][j - (stones[i - 1] as usize)] + stones[i - 1], ) }; } } sum - 2 * dp[n][m] } } ``` #### JavaScript ```js /** * @param {number[]} stones * @return {number} */ var lastStoneWeightII = function (stones) { let s = 0; for (let v of stones) { s += v; } const n = s >> 1; let dp = new Array(n + 1).fill(0); for (let v of stones) { for (let j = n; j >= v; --j) { dp[j] = Math.max(dp[j], dp[j - v] + v); } } return s - dp[n] * 2; }; ``` ### 方法二 #### Python3 ```python class Solution: def lastStoneWeightII(self, stones: List[int]) -> int: s = sum(stones) m, n = len(stones), s >> 1 dp = [0] * (n + 1) for v in stones: for j in range(n, v - 1, -1): dp[j] = max(dp[j], dp[j - v] + v) return s - dp[-1] * 2 ``` #### Java ```java class Solution { public int lastStoneWeightII(int[] stones) { int s = 0; for (int v : stones) { s += v; } int m = stones.length; int n = s >> 1; int[] dp = new int[n + 1]; for (int v : stones) { for (int j = n; j >= v; --j) { dp[j] = Math.max(dp[j], dp[j - v] + v); } } return s - dp[n] * 2; } } ``` #### C++ ```cpp class Solution { public: int lastStoneWeightII(vector& stones) { int s = accumulate(stones.begin(), stones.end(), 0); int n = s >> 1; vector dp(n + 1); for (int& v : stones) for (int j = n; j >= v; --j) dp[j] = max(dp[j], dp[j - v] + v); return s - dp[n] * 2; } }; ``` #### Go ```go func lastStoneWeightII(stones []int) int { s := 0 for _, v := range stones { s += v } n := s >> 1 dp := make([]int, n+1) for _, v := range stones { for j := n; j >= v; j-- { dp[j] = max(dp[j], dp[j-v]+v) } } return s - dp[n]*2 } ```