代码随想录第45天|70. 爬楼梯,322. 零钱兑换,279.完全平方数

文章讲述了使用动态规划解决三个问题:爬楼梯的改进版本(用完全背包法),零钱兑换的完全背包问题,以及完全平方数的组合问题。通过详细解释递推公式和dp数组的使用,展示了动态规划在这些问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

70. 爬楼梯

开始按感觉做

class Solution {
    public int climbStairs(int n) {
        //第一版按感觉做
        //dp[i]爬到第i个台阶的方法数
        int[] dp=new int[n+1];
        //初始化
        dp[0]=1;
        dp[1]=1;

        
        for(int i=2;i<=n;i++){
            dp[i]=dp[i-1]+dp[i-2];

        }
        return dp[n];
    }
}

改进-用完全背包做

这是背包里求排列问题,即:1、2 步 和 2、1 步都是上三个台阶,但是这两种方法不一样!

需要先遍历背包再遍历物品

class Solution {
    public int climbStairs(int n) {
        //用完全背包做
        //dp[i]爬到第i个台阶的方法数
        int[] dp=new int[n+1];
        int m = 2; //有兩個物品:itme1重量爲一,item2重量爲二

        //初始化
        dp[0]=1;
        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. 零钱兑换

也是一个完全背包问题,但要注意和518.零钱兑换II的区别,

动规五部曲分析如下:

1.确定dp数组以及下标的含义

dp[j]:凑足金额为j所需钱币的最少个数

2.确定递推公式

凑足金额为j-coins[i]的最少个数是dp[j-coins[i]],那么只需加上一个钱币coins[i]即dp[j-coins[i]]+1就是dp[j],所以dp[j]要取所以dp[j-coins[i]]+1中最小的。递推公式:dp[j]=min(dpp[j-coins[i]]+1,dp[j]);

3.dp数组如何初始化

凑足总金额为0需要的钱币个数一定是0,那么dp[0]=0

其他下标应该初始化为INT_MAX,否则就会在min(dpp[j-coins[i]]+1,dp[j])比较的过程中被初始值覆盖。所以下标非-元素都应该是最大值。

4.遍历顺序

都可以,因为本题求的是最小个数,于集合是组合还是排列没有关系

5.推导dp

先遍历物品再遍历背包,dp[amount]是最终结果

代码实现

class Solution {
    public int coinChange(int[] coins, int amount) {
        //完全背包
        //dp[i]表示凑成金额为i所需的最少硬币个数
        int[] dp=new int[amount+1];
        dp[0]=0;
        for(int i=1;i<dp.length;i++){
            dp[i]=Integer.MAX_VALUE;
        }
        for(int i=0;i<coins.length;i++){
            for(int j=coins[i];j<=amount;j++){
                // if(coins[i]<=j){
                     if (dp[j - coins[i]] != Integer.MAX_VALUE) {//如果是dp[j - coins[i]等于Integer.MAX_VALUE,那么+1后溢出,变成-2147483648
                    dp[j]=Math.min(dp[j],dp[j-coins[i]]+1);

                }
                
            }
        }
        return dp[amount]>amount?-1:dp[amount];
        //或者return dp[amount]==Integer.MAX_VALUE?-1:dp[amount];
    }
}

 这道题的时候卡住了,一开始在for循环里面是写的if(coins[i]<=j)这个条件,然后出现下面用例报错: 后面优化成 if (dp[j - coins[i]] != Integer.MAX_VALUE)

 

279.完全平方数

这道题和322. 零钱兑换思路基本一致

1.dp的定义

dp[i]表示组成和为i的最少完全平方数个数

2.初始化

组成0的最少完全平方数个数是0,其他非0下标初始化为最大数Integer.MAX_VALUE

3.递推公式

 dp[j]=Math.min(dp[j],dp[j-i*i]+1); 

4.遍历顺序

这道题要求的是最少和排列还是组合没有关系,因此先遍历背包还是先遍历物品都是可以的

5.推导dp

代码实现

class Solution {
    public int numSquares(int n) {
        //dp[i]含义:组成和为i的完全平方数的最少数量
        int[] dp=new int[n+1];
        //初始化
        dp[0]=0;//组成和为0的完全平方数是0
        for(int i=1;i<dp.length;i++){
            dp[i]=Integer.MAX_VALUE;
        }
        //
        for(int i=1;i*i<=n;i++){//遍历物品
        for(int j=i*i;j<=n;j++){//遍历背包
         
        if(j>=i*i&&dp[j-i*i]!=Integer.MAX_VALUE){//这个条件加不加都可以过
             dp[j]=Math.min(dp[j],dp[j-i*i]+1);        
        }
        }
        }
        return dp[n];

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值