代码随想录 | Day37 | 动态规划 :01背包应用 分割等和子集 && 最后一块石头的重量II
动态规划应该如何学习?-CSDN博客
01背包模板 | 学习总结-CSDN博客
难点:
代码都不难写,如何想到01背包并把具体问题抽象为01背包才是关键
416.分割等和子集
416. 分割等和子集 - 力扣(LeetCode)
思路分析:
主要说一下如何转换成可以应用01背包的情景
其实就是想办法把nums数组分成两半,然后看能不能让这两半的和相等就完事
那肯定要先加起来得到sum然后取余二咯,不等于0直接滚蛋
等于的话那就sum除以2,然后在nums数组里面找一个组合,让他的和等于sum/2
听起来是不是像组合总和,emm没错包一样的,想要这么做的小伙伴也可以尝试一下
如何转换为01背包呢?
1.因为是子集,所以每个数只有选或者不选两个选项,不会有重复
2.就是把nums里面的数字当做物品,他们的价值和重量全是他们本身的数值
3.而我们背包的容量c就是sum/2这个值,只要我们得到的最大价值刚好把背包给填满了,那说明背包里面这几个数加起来就是容量(因为价值=重量=自身数值),我们就找到了这个子集,就可以返回true了
如果不是刚好填满,那肯定找不出子集加起来正好是sum
然后在这里找一个模板套就完事了
01背包模板 | 学习总结-CSDN博客
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Solution { public: bool canPartition(vector<int>& nums) { int sum=0; for(auto c:nums) sum+=c; if(sum%2!=0) return false; sum/=2; vector<int> w(nums.begin(),nums.end()); vector<int> v(nums.begin(),nums.end()); vector<int> dp(sum+1,0); for(int i=0;i<nums.size();i++) for(int j=sum;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+v[i]); if(dp[sum]==sum) return true; return false; } };
|
笔者在写01背包模板的时候用这道题做的测试,下面简单记录一下不想看的跳过就好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| class Solution { public:
bool canPartition(vector<int>& nums) { int sum=0; for(auto c:nums) sum+=c; if(sum%2!=0) return false; sum/=2; vector<int> w(nums.begin(),nums.end()); vector<int> v(nums.begin(),nums.end()); vector<int> dp(sum+1,0); for(int i=0;i<nums.size();i++) for(int j=sum;j>=w[i];j--) dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
if(dp[sum]==sum) return true; return false; } };
|
1049.最后一块石头的重量II
1049. 最后一块石头的重量 II - 力扣(LeetCode)
思路分析:
其实就是尽量把石头分成两堆,然后让这两堆的重量相差最小,这样碰完就剩下的最小
所以就和上面那道题差不多
也是把数组累加,然后把sum/2当做容量
得出以sum/2作为容量的时候,我们可以搜集到的最大重量和。
注意最后返回是sum减去两次dp[c],减去两次是因为sum/2会向下取整
sum-dp[c]一定是大于等于dp[c]的,而在题目中的意思,这个代表了还可以继续粉碎。
比如加和sum为23的话,dp[c]最大就是11,23-11-11=1就是最小了
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { public: int lastStoneWeightII(vector<int>& stones) { int sum=0; for(auto c:stones) sum+=c; int c=sum/2; vector<int> dp(c+1,0); for(int i=0;i<stones.size();i++) for(int j=c;j>=stones[i];j--) dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]); return sum-dp[c]-dp[c]; } };
|