1049 最后一块石头的重量II 这道题和之前的分割子集问题没有特别大区别,有两个特殊的地方是如何处理返回值,返回值设计是sum-2*dp[target]。重点还是需要对的动态规划的思路进行掌握
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
//将本题简化为分割子集的01背包问题
//剪支处理
if(stones.size()==0) return 0;
if(stones.size()==1) return stones[0];
//设计dp数组
vector<int> dp(15001,0);//最多只有30块石头,每块石头最多100
//dp[i]指代背包内此时装载的物品重量,i指代此时背包的容量
//题设即求是否可以将石头分割成1/2 重量
int sum=0;
for(int i=0;i<stones.size();i++){
sum+=stones[i];
}
int target=sum/2;//确定target为sum的一半
//执行递推公式
for(int i=0;i<stones.size();i++)//从石头开始遍历
for(int j=target;j>=stones[i];j--){//从大至小开始对背包容量,对大于stones[i]的情况进行剪支处理
dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]);//当背包容量比石头重量大时,比较装入较重石头
}
//返回结果
return sum-2*dp[target];
}
};
494.目标和
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
//区分特殊情况,题设nums.size()>=1
int sum=0;//使用sum记录nums之和
for(int i=0;i<nums.size();i++){
sum+=nums[i];
}
if(abs(target)>sum) return 0;//target的绝对值比和大
if ((target + sum) % 2 == 1) return 0; // 此时没有方案
int bagSize = (target + sum) / 2;//目标重量
//设计dp数组
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 一和零,这道题的关键点在于弄清楚是有两个背包,0背包和1背包,物品时数组里的数字,但是装1的是一个背包,装0的是一个背包,这两个背包条件需要并行满足
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];
}
};