給定不一樣面額的硬幣 coins 和一個總金額 amount。編寫一個函數來計算能夠湊成總金額所需的最少的硬幣個數。若是沒有任何一種硬幣組合能組成總金額,返回 -1。網絡
來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/coin-change
著做權歸領釦網絡全部。商業轉載請聯繫官方受權,非商業轉載請註明出處。函數
基本是按照這篇題解的思路code
貪心
11. 想要總硬幣數最少,確定是優先用大面值硬幣,因此對 coins 按從大到小排序
12. 先丟大硬幣,再丟會超過總額時,就能夠遞歸下一層丟的是稍小面值的硬幣排序
乘法對加法的加速
21. 優先丟大硬幣進去嘗試,也不必一個一個丟,能夠用乘法算一下最多能丟幾個遞歸
k = amount / coins[c_index] 計算最大能投幾個 amount - k * coins[c_index] 減去扔了 k 個硬幣 count + k 加 k 個硬幣 若是由於丟多了致使最後沒法湊出總額,再回溯減小大硬幣數量
最早找到的並非最優解
31. 注意不是現實中發行的硬幣,面值組合規劃合理,會有奇葩狀況
32. 考慮到有 [1,7,10] 這種用例,按照貪心思路 10 + 1 + 1 + 1 + 1 會比 7 + 7 更早找到
33. 因此仍是須要把全部狀況都遞歸完leetcode
ans 瘋狂剪枝
41. 貪心雖然得不到最優解,但也不是沒用的
42. 咱們快速算出一個貪心的 ans 以後,雖然還會有奇葩狀況,可是絕大部分普通狀況就能夠瘋狂剪枝了get
做者:ikaruga
連接:https://leetcode-cn.com/problems/coin-change/solution/322-by-ikaruga/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。io
class Solution { private int min=Integer.MAX_VALUE; public int coinChange(int[] coins, int amount) { if(coins==null||coins.length==0) return -1; Arrays.sort(coins); helper(coins,0,coins.length-1,amount); return min==Integer.MAX_VALUE?-1:min; } public void helper(int[] coins,int res,int index,int all) { if(all==0) { min=Math.min(res,min); return ; } if(index<0) //說明這種移動不能獲得一個有效值,因此直接返回。 return; for(int i=all/coins[index];i>=0&&res+i<min;i--) //這裏i取到0就會跳到下一個位置,就能夠在最上層實現移動。 { helper(coins,res+i,index-1,all-i*coins[index]); } } }
使用dp來作,讓amount從小到大增長,使得後面的dp值複用前面的class
class Solution { public int coinChange(int[] coins, int amount) { if(coins==null||coins.length==0) return -1; int[] dp=new int[amount+1]; for(int i=1;i<dp.length;i++) dp[i]=Integer.MAX_VALUE; for(int i=1;i<=amount;i++) { int min=Integer.MAX_VALUE; for(int j=0;j<coins.length;j++) { if(i-coins[j]>=0&&(dp[i-coins[j]]!=Integer.MAX_VALUE)) min=Math.min(dp[i-coins[j]]+1,min); } dp[i]=min; } return dp[amount]==Integer.MAX_VALUE?-1:dp[amount]; } }