Day43_动态规划
14. 最后一块石头的重量 II
要让最后剩下的石头的重量最小,即消磨得石头的重量越多,即让重量尽可能接近的石头两两相碰。于是可以统计石头的总重量sum,将问题转化为,在容量为sum/2的背包中放入尽可能重的石头,这样背包中的石头与没有装入背包的石头互相碰撞,最后一定能消磨到只剩
sum - dp[target] - dp[target]
的重量。
粗糙证明一下结论正确性,如果没有将背包中装入最大的重量,一定有石头本可以装入背包而没有装入背包,那么消磨掉背包中的石头后,没有装入背包的石头还需要彼此消磨,直到把本可以装进去却没装进去的部分消磨掉,相当于装进了背包,所以上述方法是正确的。
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int stones_size = stones.size();
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] - dp[target];
}
};
15. 目标和
494. 目标和
思路:
dp[j]
表示填满容量j
的种类数- d p [ j ] = ∑ d p [ j − n u m s [ i ] ] dp[j] = \sum{dp[j - nums[i]]} dp[j]=∑dp[j−nums[i]]
- 初始化
dp[0] = 1
,填满容量 0 的方法数有一种,就是不填- 外层循环遍历整个nums[]数组,内层循环倒序遍历背包容量,因为扩展到二维用的是上一行的处理结果,从前往后的话会更新前面的结果,导致后面的计算出错。
设
nums
中正数相加的和为positive_sum
则有positive - (sum - positive) = target
将问题转化为求整数之和为positive_sum = (sum + target) / 2
的方法数,使用 01 背包,求容量为positive_sum
的背包被装满的方法数
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int nums_size = nums.size();
int sum = 0;
for (int i = 0; i < nums_size; ++i) sum += nums[i];
if (abs(target) > sum) return 0;
if ((sum + target) & 1) return 0; // positive - (sum - positive) = target
int positive_sum = (target + sum) / 2; //
vector<int> dp(positive_sum + 1, 0);
dp[0] = 1; // 初始化
for (int i = 0; i < nums_size; ++i) {
for (int j = positive_sum; j >= nums[i]; j--) {
dp[j] += dp[j - nums[i]];
}
}
return dp[positive_sum];
}
};
17. 一和零
474. 一和零
思路:
经典 01 背包,只不过容量分两维,0的容量一维,1的容量一维。每个字符串带来的价值是1.
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m + 1, vector<int> (n + 1, 0));
for (string str : strs) {
int ZeroNum = 0, OneNum = 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];
}
};