今日任务
70.爬楼梯
主要思想
- 使用多重背包思路做
- 假设题目修改为每次爬1…m阶楼梯
- 这里的1…m就是物品的质量
- n就是背包的容量
- dp[j] 表示的是组合总数,求排列数,多重背包
class Solution {
public:
// 使用背包思路做
// 假设题目修改为每次爬1...m阶楼梯
// 这里的1...m就是物品的质量
// n就是背包的容量
// dp[j] 表示的是组合总数,顺序有区别
// 多重背包
int climbStairs(int n) {
vector<int> dp(n + 1, 0);
dp[0] = 1;
int m = 2;
// 先遍历背包,再遍历物品
for (int j = 1; j <= n; ++j) {
for (int i = 1; i <= m; ++i) {
if (j >= i) dp[j] += dp[j - i];
}
}
return dp[n];
}
};
322.零钱兑换
主要思想
-
dp[j]:凑足总额为j所需钱币的最少个数为dp[j]
-
确定递推
- 凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i])
- 所以dp[j] 要取所有 dp[j - coins[i]] + 1 中最小的
- 递推公式:
dp[j] = min(dp[j - coins[i]] + 1, dp[j]);
-
dp数组如何初始化
- 首先凑足总金额为0所需钱币的个数一定是0,那么dp[0] = 0;
- 考虑到递推公式的特性,dp[j]必须初始化为一个最大的数(INT_MAX),否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount + 1, INT_MAX); // 因为要取最小,所以都初始化为INT_MAX
dp[0] = 0; // 但是当可以凑整时,还是从0开始算起,非0元素都应该初始化为INT_MAX
for (int i = 0; i < coins.size(); ++i) {
for (int j = coins[i]; j <= amount; ++j) {
// 如果是初始值则直接跳过,因为无法凑整,且INT_MAX最后可能溢出
if (dp[j - coins[i]] != INT_MAX) dp[j] = min(dp[j], dp[j - coins[i]] + 1);
}
}
if (dp[amount] == INT_MAX) return -1;
return dp[amount];
}
};
279. 完全平方数
主要思想
dp
数组定义 :dp[j]
表示和为j的最少完全平方数数量- 递推:
dp[j] = min(dp[j - i * i] + 1, dp[j])
- 初始化:
dp[0] = 0, dp[1..j] = INT_MAX
class Solution {
public:
// dp[j] 表示和为j的最少完全平方数数量
// dp[j] = min(dp[j - i * i] + 1, dp[j])
// 初始化:dp[0] = 0, dp[1..j] = INT_MAX
int numSquares(int n) {
vector<int> dp(n + 1, INT_MAX);
dp[0] = 0;
for (int i = 1; i * i <= n; ++i) {
for (int j = i * i; j <= n; ++j) {
if (dp[j - i * i] != INT_MAX) dp[j] = min(dp[j], dp[j - i * i] + 1);
}
}
if (dp[n] == INT_MAX) return -1;
return dp[n];
}
};