代码随想录
这个题和之前的“416 分割等和子集”非常的类似,如果给出的stones[]数组能被分成相等的两个数组,那么剩余石头的最小重量就是0。求解思路和分割等和子集一样,只是最后的返回值不同。套用01背包,物品的重量和价值都是stones[]。
dp[j] = max(dp[j],dp[j-stones[i]]+stones[i])
for(int i = 0; i < stones.size(); i++){
for(int j = target; j >= stones[i]; j--){
dp[j] = max(dp[j],dp[j - stones[i]] + stones[i]);
}
}
整体代码实现如下:
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum = 0;
for(int i = 0; i < stones.size(); i++)
sum += stones[i];
int target = sum / 2;
vector<int> dp(target+1,0);
for(int i = 0; i < stones.size(); i++){
for(int j = target; j >= stones[i]; j--){
dp[j] = max(dp[j],dp[j - stones[i]] + stones[i]);
}
}
return sum - dp[target] * 2;
}
};
假设添加“+”或者“-”之后,加法总和为x,则减法总和为sum-x(注意这里指的是添加减号的那些数的总和),其中sum是添加符号之前的数组总和,则有
target = x + (-(sum-x)) = 2x-sum
因此可以得到x的表达式:
x = (sum + target) / 2
因此将问题转化为数组中有多少种和为x的组合,套用01背包,就是装满容量为x的背包,有多少种方法,此时的背包容量bagSize就是这里的x。
因为给定的元素都为整数,所以如果sum+target为奇数的话是不可能得到和为x的组合的,因为奇数除以2之后结果会被截断。
dp[j] += dp[j - nums[i]]
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for(int i = 0; i < nums.size(); i++)
sum += nums[i];
if((sum + target) % 2 == 1) return 0;
if(sum < abs(target)) return 0;
int bagSize = (sum + target) / 2;
vector<int> dp(bagSize+1,0);
dp[0] = 1;
for(int i = 0; i < nums.size(); i++){
for(int j = bagSize; j >= nums[i]; j--){
dp[j] += dp[j - nums[i]];
}
}
return dp[bagSize];
}
};
本题中strs 数组里的元素就是物品,每个物品都是一个,而m 和 n相当于是一个背包,两个维度的背包。
dp[i][j] = max(dp[i][j],dp[i-zeroNum][j-oneNum]+1)
for (string str : strs) { // 遍历物品
int oneNum = 0, zeroNum = 0;
for (char c : str) {
if (c == '0') zeroNum++;
else oneNum++;
}
for (int i = m; i >= zeroNum; i--) { // 遍历背包容量且从后向前遍历!
for (int j = n; j >= oneNum; j--) {
dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
}
}
}
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0)); // 默认初始化0
for (string str : strs) { // 遍历物品
int oneNum = 0, zeroNum = 0;
for (char c : str) {
if (c == '0') zeroNum++;
else oneNum++;
}
for (int i = m; i >= zeroNum; i--) { // 遍历背包容量且从后向前遍历!
for (int j = n; j >= oneNum; j--) {
dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
}
}
}
return dp[m][n];
}
};