剑指 Offer II 103. 最少的硬币数目(322. 零钱兑换)

题目:

 

 

思路:

【1】使用树的回溯方式:

【2】动态规划(本质上是将每个位置的钱数都展示出来,方便当金额加上去后可以查找到没加该硬币时候的数量)

代码展示:

动态规划:

//时间15 ms击败39.70%
//内存40.7 MB击败90.50%
//时间复杂度:O(Sn),其中 S 是金额,n 是面额数。
//一共需要计算 O(S) 个状态,S 为题目所给的总金额。
//对于每个状态,每次需要枚举 n 个面额来转移状态,所以一共需要 O(Sn) 的时间复杂度。
//空间复杂度:O(S)。数组 dp 需要开长度为总金额 S 的空间。
class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount + 1];
        //然后填充到数组中,//由于当金额为0的时候是不需要硬币的故为0
        for (int k = 1; k < dp.length; k++){
            dp[k] = 77777;
        }
        //这里是遍历每个金额数的最小使用硬币数,如果金额是100000虽然1-100000都需要遍历
        //但是在计算机中这样遍历的速度是很快的
        for (int i = 1; i <= amount; i++) {
            for (int j = 0; j < coins.length; j++) {
                //这里判断是面值小于金额才会计算,防止溢出数组
                if (coins[j] <= i) {
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] == 77777 ? -1 : dp[amount];
    }
}


//这里如果是采用默认的new int 产生的0花费远比自主定义初始值的要慢
//时间10 ms击败99.16%
//内存40.9 MB击败67.15%
class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp=new int[amount+1];
        for(int k=0;k<dp.length;k++){
            dp[k]=77777;
        }
        dp[0]=0;
        for(int i=0;i<coins.length;i++){
            for(int j=coins[i];j<=amount;j++){
                    dp[j]=Math.min(dp[j-coins[i]]+1,dp[j]);
            }
        }
        return dp[amount]==77777?-1:dp[amount];
    }
}

 

使用树的回溯方式:

//时间38 ms击败10.80%
//内存41 MB击败60.61%
//时间复杂度:O(Sn),其中 S 是金额,n 是面额数。
//一共需要计算 S 个状态的答案,且每个状态 F(S) 由于上面的记忆化的措施只计算了一次,而计算一个状态的答案需要枚举 n 个面额值,所以一共需要 O(Sn) 的时间复杂度。
//空间复杂度:O(S),我们需要额外开一个长为 S 的数组来存储计算出来的答案 F(S) 。
class Solution {
    public int coinChange(int[] coins, int amount) {
        if (amount < 1) {
            return 0;
        }
        return coinChange(coins, amount, new int[amount]);
    }

    private int coinChange(int[] coins, int rem, int[] count) {
        if (rem < 0) {
            return -1;
        }
        if (rem == 0) {
            return 0;
        }
        if (count[rem - 1] != 0) {
            return count[rem - 1];
        }
        int min = Integer.MAX_VALUE;
        for (int coin : coins) {
            int res = coinChange(coins, rem - coin, count);
            if (res >= 0 && res < min) {
                min = 1 + res;
            }
        }
        count[rem - 1] = (min == Integer.MAX_VALUE) ? -1 : min;
        return count[rem - 1];
    }
}

 

posted @ 2023-04-10 15:07  忧愁的chafry  阅读(21)  评论(0编辑  收藏  举报