这道题目可能会首先想到贪心,但从第一个例子来看,贪心无法得到正确答案。
暴搜也可以得到答案,但时间复杂度是指数级别的。
我们发现,最后剩下的值一定可以表示为
我们将正数放在一起,负数放在一起,相当于求A-B的最小值。
A+B = sum
所以求sum-2B的最小值,B的值不能超过sum/2, 问题是从数组中选取一些数,试得构成不超过sum/2最大的那一个。
注意,还需要证明,满足这样条件要求的方案一定是合法的。这就是0和1背包问题。
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
// dp[i][j] 表示前i个石头按顺序添加正负号是否能凑出j
int sum = accumulate(stones.begin(), stones.end(), 0);
int n = stones.size(), m = sum / 2;
vector<vector<int>> dp(n + 1, vector<int>(m + 1));
dp[0][0] = true;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
if (j >= stones[i - 1]) {
dp[i][j] = dp[i - 1][j] | dp[i - 1][j - stones[i - 1]];
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
for (int j = m; j >= 0; j--) {
if (dp[n][j]) {
return sum - 2 * j;
}
}
return 0;
}
};