LeetCode322 Coin Change --------常规DP解法与一种高效的贪心解法

LeetCode322 硬币面值组合问题

题目描述: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.

这题很经典,题意就是说给定一个数值和一定面值的金币,在硬币数目无限的情况下,找出最少硬币数目的组合方式,没有组合就返回-1。

读完题目,就立刻想到了DP的解法。

思想大致是, amount的最小组合数目  = amount减去各个硬币面值的最小组合数 + 1

给出DP的递归求解公式:

count[amount] = min{ count[amount - coins[i] ] } , 0 <= i < n;

这里count[amount] 表示组合出amount数值所需要的最小硬币数目,coins是硬币面值的数组。

根据这个公式,我们能轻松的给出伪代码:

coinChange(int[] coins, int amount):

let count[0, 1 ... amount+1] be a new array
foreach i:
     count[i] = Max.value
for i = 0 to amount + 1:
    if(i == 0) count[0] = 0
    else:
        let l be a new list
        for k = 0 to coins.length:
            if(i - coins[k] >= 0) list.add(count[i-coins[k]] + 1);
        count = getMin(l) // get max value above zero in l
return count[amount] = Max.value ? -1:count[amount]
    

提交之后发现运行时间排名很低,特地学习了一下用时最少的解法。

第二种解法是一种基于贪心的递归解法:
大致思路就是对硬币面值先进行一次排序,并使用一个全局变量记录组合数。

从最大的硬币面值开始,计算每个硬币在组合中的最大数目,然后依次减小这个数目,递归计算,记录组合数,如果小于全局变量就更新。

代码如下:

private int res = Integer.MAX_VALUE;
    public int coinChange(int[] coins, int amount) {
        Arrays.sort(coins);
        coinChange(coins, amount, coins.length-1, 0);
        return res==Integer.MAX_VALUE ? -1 : res;
    }
    
    // 
    private void coinChange(int[] coins, int amount, int cur, int count) {
        if(cur < 0)
            return; // stop of recursion coinChange
        
        int i = amount / coins[cur];    // The most no. of coins[cur]
        if(amount % coins[cur] == 0) {
            res = Math.min(res, count + i);
            return;
        }
        
        for(; i>=0; i--) {
            if(count+i+1 >= res) {
                return;
            }
            coinChange(coins, amount-coins[cur]*i, cur-1, count+i);
        }
    }

  

猜你喜欢

转载自www.cnblogs.com/siren27/p/11300472.html