代码随想录算法训练营第36天 | 1049.最后一块石头的重量Ⅱ、494.目标和、474.一和零
文章目录
1049.最后一块石头的重量Ⅱ
解题思路
本题可以将石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就可以转化为0-1背包问题求解。
动规五部曲:
- 确定dp数组及下标的含义:dp[j] 表示容量为 j 的背包,最多可以背最大重量为 dp[j]
- 确定递归公式:dp[j] = max(dp[j],dp[j-stones[i]]+stones[i])
- dp数组的初始化:题目中给出了石头数量和重量的范围,要求的 target 取最大重量的一半,取到15000
- 确定遍历顺序:物品遍历的 for 循环放在外层,遍历背包的 for 循环放在内层,内层 for 循环倒序遍历
- 举例推导dp数组
代码实现
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
vector<int> dp(15001, 0);
int sum = 0;
for (int i = 0; i < stones.size(); i++) {
sum += stones[i];
}
int target = sum / 2;
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];
}
};
题目总结
本题和上一题分割等和子集的思路是一样的,只是最后对dp[target]的处理方式不同。
494.目标和
解题思路
- dp数组及下标含义:填满 j 这么大容积的包,有 dp[j] 种方法
- 确定递推公式:dp[j]=dp[j]+dp[j-nums[i]]
- dp数组初始化:dp[0]=1
- 确定遍历顺序:遍历物品外循环,遍历背包内循环,内循环倒序
- 举例推导dp数组
代码实现
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 (abs(target) > sum)
return 0;
if ((target + sum) % 2 == 1)
return 0;
int bagSize = (target + sum) / 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];
}
};
题目总结
当题目中问有多少种方法可以凑成目标和时,可以使用背包,但对于像组合总和这种题目中要求的时每种方法的具体的组合时,还是考虑使用回溯算法
474.一和零
解题思路
- 确定 dp 数组以及下标的含义:dp[i][j]:最多有 i 个0和 j 个1的strs的最大子集的大小为 dp[i][j]
- 确定递推公式:dp[i][j] 可以由前一个strs里的字符串推导出来,strs里的字符串有 zeroNum 个0,oneNum 个1。
dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1) - dp数组初始化:直接初始为0
- 确定遍历顺序:外层for循环遍历物品,内层for循环遍历背包容量且从后向前遍历
- 举例推导 dp 数组
代码实现
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 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];
}
};
题目总结
本题要求是给定背包容量,装满背包有多少种方法,本质是有两个维度的0-1背包。