参考
题目一:LeetCode 70. 爬楼梯
这个题之前已经做过,因为题目中给出一次可以1个或者2个台阶,所以这个题比较简单,但是如果改成一个可以爬m个台阶,就需要用完全背包的解法来做 了。
- 确定dp数组及其下标的含义
dp[j]:爬到第j个台阶,有dp[j]中方法 - 确定递推公式
dp[j] += dp[j - i] - dp数组初始化
dp[0] = 1,其他初始化为0 - 确定遍历顺序
爬楼梯的过程是个排列问题,爬一个台阶+爬两个台阶与爬两个台阶+爬一个台阶是不一样的,因此外层循环遍历背包,内层循环遍历物品。
5.举例推导dp数组
n = 3
dp[0] = 1
dp[1] = dp[0] = 1
dp[2] = dp[0] + dp[1] = 2
dp[3] = dp[2] = dp[1] = 3
完整的代码实现如下:
class Solution {
public:
int climbStairs(int n) {
vector<int> dp(n+1,0);
dp[0] = 1;
int m = 2; //对于本题,m = 2
for(int j = 0; j <= n; j++){ //遍历背包
for(int i = 1; i <= m; i++){ //遍历物品
if(j >= i)
dp[j] += dp[j-i];
}
}
return dp[n];
}
};
题目二:LeetCode 322. 零钱兑换
- 确定dp数组及其下标的含义
dp[j]:凑足总额为j所需钱币的最少个数为dp[j] - 确定递推公式
dp[j] = min(dp[j],dp[j-coins[i]] + 1)
- dp数组初始化
dp[0] = 0,其余初始化为INT_MAX - 确定遍历顺序
这个题不用关心是排列还是组合,只需要关注钱币的最少个数即可,因此两种遍历顺序都可以。 - 推导dp数组
coins = [1,2,5],amount = 5
dp = [0,1,1,2,2,1]
完整的代码实现如下:
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 = coins[i]; j <= amount; j++){
if (dp[j - coins[i]] != INT_MAX)
dp[j] = min(dp[j],dp[j-coins[i]]+1);
}
}
return dp[amount] == INT_MAX ? -1 : dp[amount];
}
};
题目三:LeetCode 279.完全平方数
- 确定dp数组及其下标的含义
dp[j]:和为j的完全平方数的最少数量为dp[j] - 确定递推公式
dp[j] = min(dp[j - i * i] + 1, dp[j])
- dp数组初始化
dp[0] = 0,其余初始化为INT_MAX - 确定遍历顺序
本题求的是最少个数,因此两种遍历顺序都是可以的。 - 举例推导dp数组
n = 5
dp = [0,1,2,3,1,2]
完整的代码实现如下:
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n + 1, INT_MAX);
dp[0] = 0;
for (int i = 0; i <= n; i++) { // 遍历背包
for (int j = 1; j * j <= i; j++) { // 遍历物品
dp[i] = min(dp[i - j * j] + 1, dp[i]);
}
}
return dp[n];
}
};