剑指 Offer II 103. 最少的硬币数目——动态规划Java实现

目录

1.题目

2.思路

时间复杂度——O(n * amount)

空间复杂度——O(amount + 1)

3.结果


1.题目

2.思路

        如果数据范围小一点,直接普通的BFS,DFS都能解决。我们先来分析一下时间复杂度,假如是普通的BFS而言,硬币数组的长度为n, amount 最大值为10000.那么我们每一次都可以选择n个硬币。我们最多选择的次数为amount / coins[]的最小值 + 1,令其为cnt.相当于总共需要变量cnt次。最终时间为n ^ cnt。n最大值为12的话,coins数组最小值为1,那么cnt最大为10000.所以最终时间复杂度为(12 ^ 10000),所以妥妥的超时...........用普通的DFS也是一样的,会超时。

        超时的根本原因在于计算了许多重复的值,而这些值没有被保存下来,所以导致时间复杂度非常高。这样优化的思路就可以从普通的搜索转化为记忆化搜索,然后记忆化搜索 和 动态规划是可以相互转化的。

        记忆化搜索,相当于从上往下递归。动态规划相当于从下往上递推。个人比较喜欢写的动态规划。动态规划三部曲。

  • 定义:dp[i] :代表组成和为i所需的最少硬币数量。(假如组不成这个数,那么赋值一个很大的数即可。通常赋值整数的最大值)
  • 初始化:dp[0] = 0.其他所有的数dp[i] = max
  • 状态转移:遍历所有的硬币数组coins[],dp[i] = Math.min(dp[i],dp[i - coin] + 1);

时间复杂度——O(n * amount)

一维动态规划

空间复杂度——O(amount + 1)

借助dp[]数组

class Solution {
    public int coinChange(int[] coins, int amount) {
        // dp[i]:组成和为i的最少的硬币个数。
        int n = coins.length;
        int[]dp = new int[amount + 1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        for(int i = 1; i <= amount; i++){
            for(int coin : coins){
                if(i - coin >= 0){
                    if(dp[i - coin] >= Integer.MAX_VALUE)continue;
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                    
                }
            }
            
        }
        return dp[amount] >= Integer.MAX_VALUE ? -1 : dp[amount];
    }
}

注意这里如果是赋值为整数的最大值的话,容易越界,比如原本dp[i-coin] = 2147483647,然后再加1,由于整数越界,就会导致结果变成-2147483648。这样再和dp[i]取最小值的话就会出问题。

所以在初始化的时候,可以选择赋值max = amount + 1.因为这个数已经大于最大的硬币个数了,因为coin最小值为1。并且这样不会越界。

class Solution {
    public int coinChange(int[] coins, int amount) {
        // dp[i]:组成和为i的最少的硬币个数。
        int n = coins.length;
        int[]dp = new int[amount + 1];
        Arrays.fill(dp, amount + 1); //如果这里设置成Integer.MAX_VALUE,小心越界。因为后面有+1操作,越界后就变成负数,然后取最小的话,答案就会出错。
        // 因为硬币最少都是1,所以最多需要amount个数,所以这里赋值一个不可能的数amount+ 1
        dp[0] = 0;
        for(int i = 1; i <= amount; i++){
            for(int coin : coins){
                if(i - coin >= 0){
                    // if(dp[i - coin] >= Integer.MAX_VALUE)continue; //如果上面数组赋值为Integer.MAX_VALUE,这里可以提前判断退出,也不会出错。
                    dp[i] = Math.min(dp[i], dp[i - coin] + 1);
                    
                }
            }
            
        }
        return dp[amount] > amount ? -1 : dp[amount];
    }
}

3.结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值