70. 爬楼梯 (进阶)
思路:本题是一个斐波那契的问题,但是也符合完全背包问题,这里用完全背包来解。
动态规划五步曲:
- dp[j] 表示到达第j层共有dp[j]种不同的方法
- 求排列问题:递推公式:dp[j] += dp[j - i]
- 初始化dp[0] = 1
- 求排列数问题,先遍历背包容量,再遍历物品
- 举例说明
class Solution {
public int climbStairs(int n) { // 使用背包的方法
// dp[j] 表示到达第j层共有dp[j]种不同的方法
int[] dp = new int[n + 1];
// 递推公式:dp[j] += dp[j - i]
// 初始化
dp[0] = 1;
for (int j = 0; j <= n; j++) {
for (int i = 1; i <= 2; i++) {
if (j >= i) dp[j] += dp[j - i];
}
}
return dp[n];
}
}
322. 零钱兑换
思路:动态规划五步曲:
- dp[j] 表示总额为j的组合使用的最少硬币个数为dp[j]
- dp[j] 需要考虑使用coins[i],和不使用coins[i]
所以递推公式:dp[j] = min(dp[j], dp[j - coins[i]] + 1)
- 初始化dp[0] = 0,代表凑成0需要的硬币个数为0,其他初始化成最大值。
- 本题两种遍历方式都可以,选择先遍历物品再遍历背包容量。
- 举例说明
class Solution {
public int coinChange(int[] coins, int amount) {
// dp[j] 表示总额为j的组合使用的最少硬币个数为dp[j]
int[] dp = new int[amount + 1];
// 递推公式:dp[j] = min(dp[j], dp[j - coins[i]] + 1)
// 初始化
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
dp[i] = Integer.MAX_VALUE;
}
// 遍历顺序
for (int i = 0; i < coins.length; i++) {
for (int j = coins[i]; j <= amount; j++) {
if (dp[j - coins[i]] < Integer.MAX_VALUE) {
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
}
}
}
if (dp[amount] != Integer.MAX_VALUE) return dp[amount];
return -1;
}
}
279.完全平方数
思路:本题与上一题思路基本相同,直接动态规划五步曲
- dp[j] 表示和为j的完全平方数的最少数量为dp[j]
- 推导公式:dp[j] = min(dp[j], dp[j - i * i] + 1)
- 初始化dp[0] = 0,其他初始化为最大值
- 同样是两种遍历顺序都可以,这里选择先遍历物品再遍历背包容量
- 举例说明
class Solution {
public int numSquares(int n) {
// dp[j] 表示和为j的完全平方数的最少数量为dp[j]
int[] dp = new int[n + 1];
// 递推公式:dp[j] = min(dp[j], dp[j - i * i] + 1)
// 初始化
dp[0] = 0;
for (int i = 1; i <= n; i++) {
dp[i] = Integer.MAX_VALUE;
}
for (int i = 1; i <= Math.sqrt(n); i++) {
for (int j = i * i; j <= n; j++) {
if (dp[j - i * i] < Integer.MAX_VALUE) {
dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
}
}
}
return dp[n];
}
}