Leetcode-322:零錢兌換

題目描述:

思路:參考自《程序員代碼面試指南》--左程云著

這是一道經典的動態規劃方法,我們可以構造一個dp數組,如果arr的長度為N,則dp數組的行數為N,列數為aim+1,dp[i][j] 的含義是:在可以任意使用arr[0..i]貨幣的情況下,組成j所需要的最小張數。

明白以上定義后我們初始化第一行與第一列,第一行dp[0][0..aim]中每一個元素dp[0][j]表示用arr[0]貨幣找開面額 j所需要的最少貨幣數,此時我們只能選取arr[0]這一張貨幣,所以只有arr[0]的整數倍的面額錢才可以找開,例如當arr[0]=3,aim=10時,只能找開3,6,9的貨幣,而其他面額的則無法找開,所以將arr[0][3,6,9]初始化為1,2,3 除此之外其他值初始化為整形int的最大值INT_MAX表示無法找開。對于第一列dp[0..n][0] 中的每一個元素dp[i][0]表示用arr[i]組成面額為0的錢的最少貨幣數,完全不需要任何貨幣,直接初始化為0即可。

對于剩下的任意dp[i][j],我們依次從左到右,從上到下計算,dp[i][j]的值可能來自下面:

  • 完全不使用當前貨幣arr[i]的情況下的最少張數,即dp[i-1][j]的值
  • 只使用1張當前貨幣arr[i]的情況下的最少張數,即dp[i-1][j-arr[i]]+1
  • 只使用2張當前貨幣arr[i]的情況下的最少張數,即dp[i-1][j-2*arr[i]]+2
  • 只使用3張當前貨幣arr[i]的情況下的最少張數,即dp[i-1][j-3*arr[i]]+3
  • ......

以上所有情況中,最終取張數最小的,
即dp[i][j] = min( dp[i-1][j-karr[i]]+k )( k>=0 )
=>dp[i][j] = min{ dp[i-1][j], min{ dp[i-1][j-x
arr[i]]+x (1<=x) } } 接下來令x = y+1
=>dp[i][j] = min{ dp[i-1][j], min{ dp[i-1][j-arr[i]-yarr[i]+y+1 (0<=y) ] } }
又有 min{ dp[i-1][j-arr[i]-y
arr[i]+y (0<=y) ] } => dp[i][ j-arr[i] ] ,(這步是這么來的:這個式子與上面的式子只相差了個1,說明這個式子少用了一個arr[i]。表達過來就是使用前i個硬幣構成 j-arr[i]這個數。)
所以,最終有:dp[i][j] = min{ dp[i-1][j], dp[i][j-arr[i]]+1 }。
如果j-arr[i] < 0,即發生了越界,說明arr[i]太大了,用一張都會超過錢數j,此時dp[i][j] = dp[i-1][j]。

代碼:

class Solution {
    public int coinChange(int[] coins, int amount) {
        int len = coins.length;
        int[][] dp = new int[len][amount+1];
        
        //初始化第0行,也就是只用coins[0]時
        for(int i=1;i<amount+1; i++){
            dp[0][i] = Integer.MAX_VALUE;
            if(i>=coins[0]&&dp[0][i-coins[0]]!=Integer.MAX_VALUE){
                dp[0][i] = dp[0][i-coins[0]]+1;
            }
        }
        
        for(int i = 1; i< len; i++){
            for(int j=1; j< amount+1; j++){
                int left = Integer.MAX_VALUE;
                if(j>=coins[i] && dp[i][j-coins[i]]!=Integer.MAX_VALUE){
                    left = dp[i][j-coins[i]]+1;
                }
                dp[i][j] = Math.min(dp[i-1][j],left);
            }
        }
        
        return dp[len-1][amount] == Integer.MAX_VALUE?-1:dp[len-1][amount];
    }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,778評論 0 33
  • 《程序員代碼面試指南-左程云》筆記 第一章 棧和隊列 設計一個有getMin功能的棧 實現一個特殊的棧,在實現棧的...
    xiaogmail閱讀 18,501評論 2 19
  • 動態規劃(Dynamic Programming) 本文包括: 動態規劃定義 狀態轉移方程 動態規劃算法步驟 最長...
    廖少少閱讀 3,338評論 0 18
  • 下一課,我們就學課文《一分鐘》了, 就是講得:“做事不能拖拖拉拉。”
    劉俊艷閱讀 177評論 0 0
  • 母親 你的頭發白了 你的眼紋又多了 你的膚色更深了 你的動作也不那么靈活了 你逐漸老去 卻孕育了我新的生命 我的光...
    江小昨閱讀 246評論 0 3