leetcode:Coin Change

来源:互联网 发布:数据加密不属于计算 编辑:程序博客网 时间:2024/05/22 13:24

原题:

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:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)

Example 2:
coins = [2], amount = 3
return -1.

Note:
You may assume that you have an infinite number of each kind of coin.

题意:给一些不同面额的硬币和一个数值,给出能凑出这个面额的最少的硬币数量。


解题思路:这个题很容易想到用动态规划,我的思路是,先凑出两个比这个数值小的数,然后由这两个数再凑成这个数值(在实现时遍历了所有的这样的两个数),因为是动态规划,凑这两个数值比较小的数的硬币数是可以知道的。这个算法虽然是动态规划,但是复杂度也是O(amount^2),而且空间复杂度是O(amount),结果超时。

其实总体思路是对的,但错在“遍历所有的这样的两个数”,应该是去遍历所有的硬币,而不是数,因为硬币数量远小于数值。这种算法时间复杂度是O(amount*coins.length)。

动态规划的核心思想是假设有2,3,5三种面额,需要凑成amount,那么一定是取 1+(amount-2),1+(amount-3),1+(amount-5)这三种数量中最少的,对于(amount-2),(amount-3)和(amount-5)的计算,是递归向下进行的。


代码如下:

public static int coinChange(int[] coins, int amount) {    if (coins == null || coins.length == 0 || amount <= 0)        return 0;    int[] minNumber = new int[amount + 1];    for (int i = 1; i <= amount; i++) {        minNumber[i] = Integer.MAX_VALUE;        for (int j = 0; j < coins.length; j++) { //遍历所有的硬币面额            if (coins[j] <= i && minNumber[i - coins[j]] != Integer.MAX_VALUE) //要判断是否可以生成这个面额                minNumber[i] = Integer.min(minNumber[i], 1 + minNumber[i - coins[j]]);        }    }    if (minNumber[amount] == Integer.MAX_VALUE)        return -1;    else        return minNumber[amount];}

上面思路的空间复杂度是O(amount)。


还有一种递归的实现方式,空间复杂度应该小于上者,但是比上面慢多了。在使用递归的动态规划中,使用了HashMap来保存已经计算过的数据,从而避免了重复计算,理论上说使用HashMap保存时,空间复杂度会降低。总的思路跟上面类似。

代码如下:

   HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();//dp还可以用hashMap存放已经计算的数据,第一次尝试    public int coinChange(int[] coins, int amount) {            if(amount==0){    return 0;    }        for(int coin:coins){    map.put(coin, 1);    }        int res = getCoins(coins, amount);        if(res==Integer.MAX_VALUE){    return -1;    }        return res;    }        //获取指定数目的钱,需要多少硬币    public int getCoins(int[] coins,int amount){        if(map.containsKey(amount)){    return map.get(amount);    }        int minVal = Integer.MAX_VALUE;        for(int coinVal:coins){        int cur = minVal;    if(amount>coinVal){    cur = getCoins(coins, amount-coinVal);    }    if(minVal>cur){    minVal = cur;    }    }        if(minVal!=Integer.MAX_VALUE){    map.put(amount, minVal+1);    return minVal+1;    }else{    map.put(amount, Integer.MAX_VALUE);        return Integer.MAX_VALUE;    }            }

 


0 0