322. 零钱兑换

143 阅读2分钟

思路:动态规划

  • 每种物品可以重复无限次使用,为完全背包问题
  • dp[i]:凑足总额为i所需钱币的最少个数为dp[i]
  • 递推公式:dp[i] = min(dp[i - coins[j]] + 1, dp[i]);
    • 凑足总额为i-coins[j]的最少个数为dp[i-coins[j]],再加上一个钱币coins[j]dp[i-coins[j]]+1就是dp[i]
    • dp[i]要取所有dp[i-coins[j]] + 1中最小的,采取滚动数组的方式来计算min。
  • 由于是找个数,排列or组合都可以,所以本题内外层遍历顺序可以交换

写法1:外层遍历amount,内层遍历coins

class Solution {
    public int coinChange(int[] coins, int amount) {
        int length = coins.length;
        int[] dp = new int[amount + 1];//因为还要凑0
        // 一定要fill 否则后面求min永远是0
        Arrays.fill(dp, amount + 3);//默认值,凑法最大也就是amount种,1*amount,dp[k]=amount+3表示凑k块钱是凑不出来的
        dp[0] = 0;//凑0的方法数
        for (int i = 1; i <= amount; i++) {
            for (int j = 0; j < length; j++) {
                //i - coins[j] >= 0防止越界,不可能拿5元硬币去凑1快钱;
                if (i - coins[j] >= 0 ) {//coins = [2] amount = 3拿2凑3是凑不出来的,dp[3] = amount + 3,dp[1] = amount + 3 + 1
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);//滚动更新凑i块钱的方法数
                }
            }
        }
        return dp[amount] == amount + 3 ? -1 : dp[amount];
    }
}

写法1:外层遍历coins,内层遍历amount

class Solution {
    public int coinChange(int[] coins, int amount) {
        int length = coins.length;
        int[] dp = new int[amount + 1];//因为还要凑0
        Arrays.fill(dp, amount + 3);//默认值,凑法最大也就是amount种,1*amount,dp[k]=amount+3表示凑k块钱是凑不出来的
        dp[0] = 0;//凑0的方法数
        for (int i = 0; i < length; i++) {
            for (int j = 1; j <= amount; j++) {
                if (j - coins[i] >= 0 ) {
                    dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
                }
            }
        }
        return dp[amount] == amount + 3 ? -1 : dp[amount];
    }
}