声明:以下所有题目套路以及部分题目代码均来自于labuladong的算法小抄
01背包
套路:
初始化
for(状态1:状态)
for(状态2:状态)
{
if(背包装不下)
dp=
else
{
dp=f(选择)(求最值就用max求方法数就用+)
}
}
leetcode494 目标和(变体01背包)
给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。
返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/target-sum
- 易错点:在遍历dp数组时要分成背包装的下与装不下两种情况
- 难点:将+ -两种运算变成只有+一种运算(数学方法得出+的次数,不装入+就是-
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
//dp[N][W] 前N个数目标数为W的方法数
//选择:装入 不装入
//状态,数组,目标数
//初始化dp[0][W]=0;dp[0][0]=1;
int sum = 0;
for (int i = 0; i < nums.size(); i++) sum += nums[i];
if (target > sum) return 0; // 此时没有方案
if ((target + sum) % 2 == 1) return 0; // 此时没有方案
int bagSize = (target + sum) / 2;
vector<vector<int>> dp(nums.size()+1,vector<int> (bagSize+1));
for(int i=0;i<bagSize+1;i++)
{
dp[0][i]=0;
}
dp[0][0]=1;
for(int i=1;i<=nums.size();i++)
{
for(int j=0;j<=bagSize;j++)
{
if(j-nums[i-1]<0)//if(j-nums[i]<0)!!!!!总是错//背包装不下
dp[i][j]=dp[i-1][j];
else
dp[i][j]=dp[i-1][j-nums[i-1]]+dp[i-1][j];//背包装得下
}
}
return dp[nums.size()][bagSize];
}
};
子集背包
leetcode416
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
class Solution {
public:
bool canPartition(vector<int>& nums) {
//dp[N][W]转化为可装载重量为sum/2的背包和N个物品,每个物品重量为sum[i],是否存在一种装法把背包装满。
//初始化dp[0][..]=false dp[...][0]=true.
//选择:装与不装。状态:剩余容量减少,剩余容量不变,
int sum=0;
for(int num:nums) sum=sum+num;
if(sum%2!=0) return false;//如果sum是奇数,直接pass
sum=sum/2;
bool **dp=new bool* [nums.size()+1];
for (int i=0;i<=nums.size();i++)
{
dp[i]=new bool[sum+1];
for(int j=0;j<=sum;j++)
{
dp[i][j]=false;
dp[i][0]=true;
}
}
for(int i=1;i<=nums.size();i++)
{
for(int j=1;j<=sum;j++)
{
if(j-nums[i-1]<0)//背包容量不足,不能装入物品,维持i-1个物品时的判断
dp[i][j]=dp[i-1][j];
else
{
dp[i][j]=dp[i-1][j]|dp[i-1][j-nums[i-1]];//选择装入或者不装入
}
}
}
return dp[nums.size()][sum];
}
};
完全背包
leetcode518 零钱兑换2
给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。
- 易错点 dp[i][j]=dp[i][j-coins[i-1]]+dp[i-1][j];注意在01背包里dp[i][j]=dp[i-1][j-nums[i-1]]+dp[i-1][j]
class Solution {
public:
int change(int amount, vector<int>& coins) {
//dp[i][j]对于前i个物品,背包容量为j时,有dp[i][j]种方法可以装满背包
//选择:放入背包or不放入背包
//状态 可选择的物品,背包容量
//初始化 j=0时dp[i][0]=1,这我真没法理解,凑零元一个硬币都不加也能算一种方案吗
//dp[0][j]=0;
//状态转移:放入背包dp[i][j]=dp[i][j-coins[i-1]]//这里注意:为什么时dp[i][j-coins[i-1]
//而非dp[i-1]][j-coins[i-1]]呢,因为这是个无限硬币的组合类问题,所以可以一直装下去直到选择不装。。
// 不放入背包dp[i][j]=dp[i-1][j]
vector<vector<int>> dp(coins.size()+1,vector<int>(amount+1,0));
for(int i=0;i<=coins.size();i++)//注意赋值全面
dp[i][0]=1;//初始化
for(int i=1;i<=coins.size();i++)
{
for(int j=1;j<=amount;j++)
{
if(j-coins[i-1]>=0)//背包装得下
dp[i][j]=dp[i][j-coins[i-1]]+dp[i-1][j];
else//背包装不下
dp[i][j]=dp[i-1][j];
}
}
return dp[coins.size()][amount];
}
};
leetcode279 完全平方数
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/perfect-squares
- 最少数量题,大部分初始化为INT—MAX,状态转移时加一
class Solution {
public:
int numSquares(int n) {
vector<int> num;
for(int i=1;i*i<=n;i++)
{
num.push_back(i*i);
if(i*i>=n)
break;
}
//dp[i][j]前i个数的背包容量j 所需要最少数量
//dp[i][0]=0; dp[0][j]=int_max
//dp[i][j]=min(dp[i-1][j],dp[i][j-num[i]])
vector<vector<int>> dp(num.size()+1,vector<int>(n+1,INT_MAX));
for(int i=0;i*i<=n;i++)
{
dp[i][0]=0;
}
for(int i=1;i<=num.size();i++)
{
for(int j=1;j<=n;j++)
{
if(j-i*i>=0&&dp[i][j-num[i-1]]!=INT_MAX)//易错点:dp[i][j-num[i-1]]!=INT_MAX的判断
dp[i][j]=min(dp[i-1][j],dp[i][j-num[i-1]]+1);//易错点:num[i-1]别写成num[i]!!!!!!!!!!!!!!!!还有记得加一
else
dp[i][j]=dp[i-1][j];
}
}
return dp[num.size()][n];
}
};
1255

被折叠的 条评论
为什么被折叠?



