代码随想录算法训练营day45 | 70. 爬楼梯 (进阶),322. 零钱兑换,279.完全平方数
- 70. 爬楼梯 (进阶)
- 解法一:动态规划
- 322. 零钱兑换
- 解法一:动态规划
- 279.完全平方数
- 解法一:动态规划
70. 爬楼梯 (进阶)
教程视频:这里利用背包问题的思想拓展成每次可以爬1~m个台阶
思路:
1、dp[j]定义:到第 j 层的方法数
2、递推公式:dp[j]+=dp[j-m[i]];此时物品的重量和价值都为每次爬的台阶数
3、dp初始化:dp[0]=1;其余下标均初始化为0
4、遍历顺序:根据示例2,这是完全背包求排列问题,外层for循环正向遍历背包容量,内层遍历物品
5、打印结果
解法一:动态规划
class Solution {
public int climbStairs(int n) {
int[] m={1,2};//模拟每次能爬1~2曾台阶,表示背包问题的物品
int[] dp = new int[n+1];
dp[0]=1;
for(int j=1;j<=n;j++){
for(int i=0;i<m.length;i++){
if(j>=m[i])dp[j]+=dp[j-m[i]];
}
}
return dp[n];
}
}
322. 零钱兑换
教程视频:https://www.bilibili.com/video/BV14K411R7yv
思路:这是一个完全背包问题,其中amount为背包容量,硬币价值为物品重量,求的是最少硬币数量。
1、dp[j]定义:背包容量为 j 时使用的最少硬币数量。
2、递推公式:dp[j]=Math.min(dp[j],dp[j-coins[i]]+1);
3、dp初始化:dp[0]=0; 因为求的是最小值,其他下标要初始化为最大整数
4、遍历顺序:求的是完全背包的结果长度,组合和排列都可以,这里采用组合的求法。外层for遍历物品,内层for正序遍历背包容量
5、打印结果
解法一:动态规划
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
//初始化dp数组
dp[0]=0; //当金额为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){//这里需要判断是否为最大值,否则最大值+1会溢出为-2147483648
dp[j]=Math.min(dp[j],dp[j-coins[i]]+1);
}
}
}
return dp[amount]==Integer.MAX_VALUE? -1 : dp[amount];
}
}
279.完全平方数
教程视频:https://www.bilibili.com/video/BV12P411T7Br
思路:这是一个完全背包问题,其中 n 为背包容量,完全平方数为物品重量,求的是最少完全平方数的数量。总体与上一题322. 零钱兑换一样,这里的难点在于物品数量随背包容量变化,即物品m满足m*m<=n
1、dp[j]定义:背包容量为 j 时使用的最少完全平方数的数量。
2、递推公式:dp[j]=Math.min(dp[j],dp[j-m[i]]+1);
3、dp初始化:dp[0]=0; 因为求的是最小值,其他下标要初始化为最大整数
4、遍历顺序:求的是完全背包的结果长度,组合和排列都可以,这里采用组合的求法。外层for遍历物品,内层for正序遍历背包容量
5、打印结果
解法一:动态规划
class Solution {
public int numSquares(int n) {
int[] dp = new int[n+1];
//初始化dp
for(int i=1;i<=n;i++)dp[i]=Integer.MAX_VALUE;
for(int i=1; i*i<=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];
}
}