LeetCode-【動態規劃】-零錢兌換
阿新 • • 發佈:2018-12-09
給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函式來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1
。
示例 1:
輸入: coins = [1, 2, 5], amount = 11
輸出: 3
解釋: 11 = 5 + 5 + 1
示例 2:
輸入: coins = [2], amount = 3
輸出: -1
說明:
你可以認為每種硬幣的數量是無限的。
題解:呃,第一想法是遞迴加回溯找到組合最小值,又來了,剛寫的組合總和 Ⅳ的第一想法就是遞迴加回溯,不過結局比較慘,時間超限了。沒有意外,本題在[1,2,5] 100這條資料就超時了,總共過了15條資料,呵呵,有時候思路正確並不一定能完美解題。好吧,還是動規登場,假設dp[i]為錢數為i時需要的最少硬幣數,當i=0時,dp[0]=0,這個毫無疑問,當i>0時,直接說不好理解,那就舉個例項,[1,2,3] 3 對這個例子來說,一種情況是隻用1,數量是3,一種是用1和2,數量是2,最後是隻用3,數量是1,那問題變成了,怎樣使最終的結果為1,你可能說比較,好,誰和誰比較,呃。。。,換一個角度思考,對任意硬幣coins[j],我們有使用和不使用兩種情況,所以比較的雙方出來了,dp[i]代表使用coins[j],dp[i-coins[j]]+1代表不使用coins[j],那麼這裡為什麼又要加1呢,因為對i-coins[j]來說它加上一個coins[j]就是i了,所以這裡需要加上1,然後i-coins[j]再從前一個狀態判斷最小值,最後直到已知值dp[0]。
其實真正的過程是i從0到amount記錄每個狀態的最小值,最後執行到dp[amount]時就是最後求的最小值,這也是動規真正的執行過程,不過我們習慣從最後開始分析問題,通過確定最後的狀態與之前狀態的關係,從而確定動態轉移方程。
class Solution { public int coinChange(int[] coins, int amount) { Arrays.sort(coins); int n=coins.length; if(n==0||amount==0) return 0; int[] dp=new int[amount+1]; Arrays.fill(dp,amount+1); dp[0]=0; for(int j=0;j<n;j++){ for(int i=coins[j];i<=amount;i++){ dp[i]=Math.min(dp[i],dp[i-coins[j]]+1); } } return dp[amount]>amount?-1:dp[amount]; } }