完全背包问题
1. 物品可以重复使用 ----->完全背包----->正序遍历
2. 排列问题---->先背包后物品
3. 组合问题---->先物品后背包
4. 种类个数问题 dp[j] += dp[j-i];
初始化 vector<int>dp(n+1, 0); dp[0] = 1
6. 种类最少问题 dp[j] = min(dp[j], dp[j-coins[i]] + 1);
初始化 vector<int>dp(amount+1, INT_MAX); dp[0] = 0;
1.动态规划
dp[i] 登上i阶台阶有多少种方法
dp[i] = dp[ i - 1 ] + dp[ i - 2 ]
dp[1] = 1 dp[2] = 2
- 完全背包
条件: 可重复使用—>完全背包—>正序遍历
要求顺序—>先背包后物品
问种类 dp[ i ] += dp[ i - j ]
class Solution {
public:
int climbStairs(int n) {
// 完全背包 有循序要求(先背包后物品)
vector<int>dp(n+1, 0);
dp[0] = 1;
for(int j=1; j<=n; j++){
for(int i=1; i<=2; i++){
if(j>=i)
dp[j] += dp[j-i];
}
}
return dp[n];
}
};
322. 零钱兑换
硬币数量无限---->完全背包—>正序
内部有无顺序皆可 因为只看min—>先物品后背包 因为只看min 所以先背包后物品可以可以的
递推公式 dp[ j ] = min(dp[ j ], dp[ j-coins[i] ] + 1);
初始化 求min 则 赋值为 int的最大值 vectordp(amount+1, INT_MAX);
dp[0] = 0; 不然后面都不更新
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int>dp(amount+1, INT_MAX);
dp[0] = 0;
for(int i=0; i<coins.size(); i++){
for(int j=1; j<=amount; j++){
if(j >= coins[i] && dp[j-coins[i]] <= INT_MAX -1)
dp[j] = min(dp[j], dp[j-coins[i]] + 1);
}
}
if(dp[amount] != INT_MAX) return dp[amount];
return -1;
}
};
优化
//通过赋值以及从硬币面值开始遍历避免反复判断
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int>dp(amount+1, INT_MAX-1);
dp[0] = 0;
for(int i=0; i<coins.size(); i++){
for(int j = coins[i]; j<=amount; j++){
dp[j] = min(dp[j], dp[j-coins[i]] + 1);
}
}
if(dp[amount] == INT_MAX-1) return -1;
return dp[amount];
}
};
背包容量为n 物品为 1~ sqrt(n)
可重复—>完全背包
看最少数目–>考不考虑顺序皆可—>先背包后物品 或 先物品后背包
class Solution {
public:
int numSquares(int n) {
int m = sqrt(n);
vector<int>dp(n+1, INT_MAX-1);
dp[0] = 0;
for(int i=1; i<=m; i++){
for(int j=i*i; j<=n; j++){
dp[j] = min(dp[j], dp[j-i*i]+1);
}
}
return dp[n];
}
};