Link:
题目要求
有一堆石头,用整数数组stones表示。其中stones[i]表示第i块石头的重量。每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为x和y,且x <= y。那么粉碎的可能结果如下:
- 如果
x == y,那么两块石头都会被完全粉碎;
- 如果
x != y,那么重量为x的石头将会完全粉碎,而重量为y的石头新重量为y-x。最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回0。
核心算法和原理
- 求的其实是:将石头尽可能分成质量接近的两堆,这两堆石头的差即为最小值
- 本质上是「Leetcode 416:分割等和子集」的变种,即01背包的应用
- dp[i][j]:从前i个石头中选石头,能否组成总质量为j的石头堆
代码
class Solution { public: int lastStoneWeightII(vector<int>& stones) { int n = stones.size(); int sum = 0; for (int s: stones) { sum += s; } int target = sum / 2; vector<bool> dp(target + 1, false); dp[0] = true; int curSum = 0; for (int i = 0; i < n; i++) { curSum += stones[i]; for (int j = min(curSum, target); j >= stones[i]; j--) { dp[j] = dp[j] || dp[j - stones[i]]; } if (dp[target]) { return (sum - target) - target; } } for (int i = target; i > 0; i--) { if (dp[i]) { return (sum - i) - i; } } // only one element return stones[0]; } };
