# 代码随想录算法训练营第45天| 70. 爬楼梯(进阶)、322. 零钱兑换、279.完全平方数

70. 爬楼梯(进阶)

完成

思路:

之前做过爬楼梯,每次只爬1阶或2阶,本题可以爬1~m阶楼梯。可以转化为完全背包问题,为什么不是01背包呢?因为每个台阶层数都可以多次选择。

楼梯的总台阶数就是背包容量,每次爬的台阶就是物品的重量,要求把背包装满有多少种方法。其实也是排列问题,因为对于3阶台阶而言,1、2与2、1是两种方法,都要算进去。
排列问题需要先遍历背包,再遍历物品。

代码

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        int[] dp = new int[n+1];
        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];
            }
        } 
        System.out.println(dp[n]);
    }
}

322. 零钱兑换

完成

思路:

本题可以把总金额看成背包容量,硬币就是物品,其价值就是重量。题目要求凑成总金额所需的最少硬币数量,dp[j]代表装满容量为j的背包,最少的物品数量为dp[j]

递推公式为dp[j] = Math.min(dp[j], dp[j-coins[i]]+1),由于是取最小,初始化就不能为0了,否则会污染计算出的数据,但是dp[0]需要是0。另外需要注意,本题并不是一定能取到总金额,还有不成立的情况。

代码

class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount+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]]+1 就是 -2147483648
                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 -1;
        return dp[amount];
    }
}

279.完全平方数

完成

思路:

和上题一样。
在物品的处理上,可以把i*i作为物品,但是本题给了范围,也就是物品的最大数量是100,把这100个物品列成数组,可以减少一点计算量。

代码

class Solution {
    public int numSquares(int n) {
        // 物品
        int[] goods = {1,4,9,16,25,36,49,64,81,100,121,144,169,196,225,256,289,324,361,400,441,484,529,576,625,676,729,784,841,900,961,1024,1089,1156,1225,1296,1369,1444,1521,1600,1681,1764,1849,1936,2025,2116,2209,2304,2401,2500,2601,2704,2809,2916,3025,3136,3249,3364,3481,3600,3721,3844,3969,4096,4225,4356,4489,4624,4761,4900,5041,5184,5329,5476,5625,5776,5929,6084,6241,6400,6561,6724,6889,7056,7225,7396,7569,7744,7921,8100,8281,8464,8649,8836,9025,9216,9409,9604,9801,10000};
        int[] dp = new int[n+1];
        dp[0] = 0;
        for (int i = 1; i <= n; i++) {
            dp[i] = Integer.MAX_VALUE;
        }
        for (int i = 0; i < goods.length; i++) {
            // 剪枝
            if(goods[i]>n) break;
            for (int j = goods[i]; j <= n; j++) {
                dp[j] = Math.min(dp[j], dp[j-goods[i]]+1);
            }
        }
        return dp[n];
    }
}
  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值