Leetcode 1049. 最后一块石头的重量 II
题目链接 1049 最后一块石头的重量 II
本题思路用一句话概括本题:其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小。这样一看和前面的题目一个思路了,下面上代码:
cpp
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum = 0;
for(int i=0;i<stones.size();i++){
sum+=stones[i];
}
int target;
target = sum/2;
vector<int> dp(15005,0);//初始化
//dp[j]的含义是在容量为j的背包中,取最大价值的石头
for(int i=0;i<stones.size();i++){
for(int j=target;j>=stones[i];j--){
dp[j] = max(dp[j-stones[i]]+stones[i],dp[j]);//这里价值和重量相等
}
}
int result = sum-dp[target]-dp[target];
return result;
}
};
Leetcode 494. 目标和
题目链接 494 目标和
本题目思路比较难想:
如何转化为01背包问题呢。
假设加法的总和为x,那么减法对应的总和就是sum - x。
所以我们要求的是 x - (sum - x) = target
x = (target + sum) / 2
此时问题就转化为,装满容量为x的背包,有几种方法。
要注意dp的含义:dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法
自身感觉卡哥在视频中没讲清楚,看了一下别人的讲解觉得不错:
dp[j]=dp[j]+dp[j-nums[i]]
这个方程的意思是,如果我们要用若干个元素组成和为j的方案数,那么有两种选择:不选第i个元素或者选第i个元素。如果不选第i个元素,那么原来已经有多少种方案数就不变;如果选第i个元素,那么剩下要组成和为j - nums【i】 的方案数就等于dp[j - nums【i】]。所以两种选择相加就是dp【j】。
下面上代码:
cpp
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 left = (target+sum)/2;
vector<int> dp(left+1,0);
dp[0] = 1;
for(int i=0;i<nums.size();i++){
for(int j=left;j>=nums[i];j--){
//dp的含义是取j个元素能得到target的方案数
dp[j]=dp[j]+dp[j-nums[i]];
}
}
return dp[left];
}
};
Leetcode 474. 一和零
题目链接 474 一和零
本题也是01背包,只不过是两个维度,就是一个三位数组,下面上代码:
cpp
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 z = 0;
int y = 0;
for(char c : str){//遍历物品
if(c == '0'){
z++;
}else{
y++;
}
}
for(int i=m;i>=z;i--){//遍历容量
for(int j=n;j>=y;j--){
dp[i][j] = max(dp[i-z][j-y]+1,dp[i][j]);
}
}
}
return dp[m][n];
}
};
对于01背包又有点迷了,上课回来还要仔细思考一下