LeetCode 322. Coin Change(动态规划和回溯法)

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example 1:

Input: coins = [1, 2, 5], amount = 11
Output: 3 
Explanation: 11 = 5 + 5 + 1

Example 2:

Input: coins = [2], amount = 3
Output: -1

--------------------------------------------------------------------------------------

首先自己写了回溯法的代码,结果发现超时。

LeetCode讨论区里发现了一种回溯解法,结合一些合理的贪心剪枝。

Runtime: 1 ms, faster than 100.00% of Java online submissions for Coin Change.

代码如下,有两个剪枝的细节还没有明白

class Solution {
        
    //1 ms
    int minCount = Integer.MAX_VALUE;//通过这个全局变量进行回溯法的剪枝
    public int coinChange(int[] coins, int amount) {
        Arrays.sort(coins);
        dfs(amount, coins.length-1, coins, 0);
        return minCount == Integer.MAX_VALUE?-1:minCount;
    }
    private void dfs(int amount, int start, int[] coins, int count){
        if(start<0 || count+2>minCount) return;
        
        for (int i = amount/coins[start];i>=0;i--){
            //贪心:从最大面值的开始进行dfs,且一次尽可能的先多用最大面值。不行则回退,少用一张大面值
            int newAmount = amount - i*coins[start];
            int newCount = count + i;
            if(newAmount>0 && newCount+1<minCount)//??剪枝,只递归可能的地方
                dfs(newAmount, start-1, coins, newCount);
            else{
                if(newAmount==0 && newCount<minCount)//发现了新的最短路径
                    minCount = newCount;
                break;
            }
        }
    }
    

}

----------------------------------------------------------------------------------------------

接下来就是动态规划的方法了:

参考注释应该很容易理解

public class Solution {
    
    public int coinChange(int[] coins, int amount) {

        int[] dp = new int[amount+1];//dp[i]表示求和为i的最短长度. i = 0,1,2,....amount
        //dp[0] = 0; //求和为0的最短组合长度为0
        
        int target = 1;//求和目标 
        while(target<=amount) {
            //当已知求和目标为0,1,2,3,...target-1时的最短长度,接下来去求 求和目标为target时的最短长度
            int min = -1;//求和目标为target时的最短组合长度
            for(int coin : coins) {
                if(target >= coin && dp[target-coin]!=-1) {
                    if(min==-1) min = dp[target-coin]+1; 
                    else if(dp[target-coin]+1 < min) min = dp[target-coin]+1;
                }
                //否则min仍为-1
            }
            dp[target] = min;//得到了:求和为sum的最短长度 
            target++;
        }
        return dp[amount];
    }
    
}

猜你喜欢

转载自blog.csdn.net/qq_39638957/article/details/89307054