1049.最后一块石头的重量||(有点感觉了)
分析:
- 只有石头不相等时,才会剩下石头,所以相等的部分会两两抵消;
- 所以最后一块石头一定是两两抵消的结果,总和-抵消*2=最后一块石头
- 转换为背包问题:容量=总和/2 看最多能装多少,装满即完全抵消
思路:
- 1.dp存储:当容量为j时,装的最大重量dp[j]
- 2.dp [ j ] =max(dp [ j ],dp [ j - stones [ i ] ] + stones [ i ] )
- 3.初始化:全为0
- 4.遍历顺序:外层遍历石头,内层遍历背包容量
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int total=0;
for(auto it:stones) total+=it;
int target=total/2;
vector<int>dp(total+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 total-2*dp[target];
}
};
494.目标和
分析:
- 正数值add 负数值sub 总和sum
- add-sub=target -> add-(sum-add)=target -> add=(target+sum)/2
- 得出需要达到的正数值,转换为背包问题:装满add有几种方法
思路:
- 1.dp存储:值为 j 时有dop[j]种方法装满
- 2.dp[j]+=dp[j-nums[i]] 只要装入nums[i]刚好装满的方法都可行
- 3.初始化:dp[0]=1 不装就是一种方法
- 4.遍历顺序:外层遍历元素 内层遍历背包容量
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int total=0;
for(auto it:nums) total+=it;
if(abs(target)>total) return 0;
if((target+total)%2==1) return 0;//如果为奇数,说明add无法取整,无法得出结果
int add=(target+total)/2;
vector<int>dp(add+1,0);
dp[0]=1;
for(int i=0;i<nums.size();i++){
for(int j=add;j>=nums[i];--j){
dp[j]+=dp[j-nums[i]];
}
}
return dp[add];
}
};
474.一和零
分析:
- 分析:在满足0和1个数的同时,尽量多的装字符串
- 转化为背包问题:二维容量:zeroNum oneNum 的容量下,最多能装多少物品
思路:
- 1.dp存储:当可以装0为i个,1为j个时,最多可以装dp[i][j]个字符串
- 2.dp[i][j]=max(dp[i][j],dp[i-zeroNum][j-oneNum]+1); 装入当前值后,总数+1
- 3.初始化:全为0
- 4.遍历顺序:外层遍历字符串数组,内层两个for循环进行字符容量遍历
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>>dp(m+1,vector<int>(n+1,0));
for(int i=0;i<strs.size();i++){
int oneNum=0,zeroNum=0;
for(char it:strs[i]){//记录当前字符0和1的数量
if(it=='0') zeroNum++;
else oneNum++;
}
for(int j=m;j>=zeroNum;--j){//二维装填
for(int k=n;k>=oneNum;--k){
dp[j][k]=max(dp[j][k],dp[j-zeroNum][k-oneNum]+1);
}
}
}
return dp[m][n];
}
};
518.零钱兑换 ||(坐牢)
分析:完全背包
思路:
- 1.dp存储:价值 j 时,可以装的方法有 dp[j] 种
- 2.dp[j]+=dp[j-coins[i]]
- 3.初始化:dp[0]=1
- 4.遍历顺序:外层遍历硬币,内层遍历容量
class Solution {
public:
int change(int amount, vector<int>& coins) {
int n=coins.size();
vector<int>dp(amount+1);
dp[0]=1;
for(int i=0;i<n;i++){
for(int j=coins[i];j<=amount;j++){
cout<<dp[j]<<endl;
dp[j]+=dp[j-coins[i]];
}
}
return dp[amount];
}
};
377.组合总和IV(微微坐牢啊)
思路:
- 1.dp存储:和为 j 时,组成这个和的种数为 dp[j]
- 2.dp[j]+=dp[j-nums[i]];
- 3.初始化:dp[0]=1
- 4.遍历顺序:外层遍历容量 内层遍历元素
本题需要的是排列:所以先遍历容量(背包)
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int>dp(target+1,0);
dp[0]=1;
for(int i=0;i<=target;i++){
for(int j=0;j<nums.size();j++){
if(i-nums[j]>=0 && dp[i]<=INT_MAX-dp[i-nums[j]])
dp[i]+=dp[i-nums[j]];
}
}
return dp[target];
}
};