LeetCode | 518 Coin Change II

更新於 發佈於 閱讀時間約 6 分鐘

今天打開 leetcode,點進去它推送的 daily challenge,然後就成為了今天噩夢的開始...我要好好了解演算法了 QQ

題目是 518. Coin Challenge II,題目要求不難理解,就是規定有一個要湊出來的金額 amount,然後有一袋硬幣 coins,硬幣面額有限但數量無限,請問有多少湊法?

舉例來說,就是如果有 1、2、5 三種面額的硬幣,要湊成 5 元可以有幾種湊法,答案是 4 種:

from: LeetCode

from: LeetCode

不難理解題目的意思吧。然後真的開始寫就爆炸了,我的 code 歷經了多輪測試層層挺進,最後死在了要用 1、2、5 去湊出 500 元來,給大家看一下有多慘哈...

raw-image

所以我忍不住了,直接點開 solutions 看大神怎麼解,然後歪唷,嗯,看某...還跑去問了 ChatGPT 才知道這用的是動態規劃的解法,而這題也是動態規劃的經典題。經典是經典,但為難了我這還沒出新手村的孩砸...。

Code 是這樣子的:

var change = function(amount, coins) {
    const dp = new Array(amount + 1).fill(0);
    dp[0] = 1;

    for (const coin of coins) {
        for (let i = coin; i <= amount; i++) {
            dp[i] += dp[i - coin];
        }
    }

    return dp[amount];
}

一個陣列、兩個迴圈,簡簡單單,然後我跟 ChatGPT 拉扯了幾個小時、爬了幾篇動態規劃的文章,後來在中午吃飯時看了下面兩部影片才算是稍微知道這串 code 背後的邏輯思維是啥。我就稍微記錄一下我的理解哈,如果有理解錯拜託小力鞭 QQ



所以這串 code 到底搞了什麼事情,我嘗試理解拆解了一下。

1.) 建立了一個長度為 amount + 1 的陣列 "dp",它是用來儲存湊成金額 "i" 的方法數量的陣列。因為還沒開始更新,所以先把值都設為 0。

好了,為何要一個個把金額 i 列出來?題目不是只要求要湊到 amount 就好嗎?我後來理解這就是有關動態規劃的 "把大問題拆成很多小問題,然後由小問題的解組合成大問題的解" 的概念所在,很渾沌對吧?用下面例子說應該會比較清楚一點...

2.) 先建立了一個陣列後,把 dp[0] 設為 1,這裡的意思很簡單,就是湊成金額 0 的方法只有一個,就是都不拿任何硬幣。

raw-image

3.) 開始第一遍遍歷 (coin = 1),我們計算出使用硬幣面額 1 去湊出目標金額 i (1 ~ 5) 的方法有幾種。答案是都是一種,因為 "1 = 1"、"2 = 1 + 1"、"3 = 1+ 1 + 1"...以此類推,到這裡都還不難理解齁。

raw-image

4.) 第二遍遍歷 (coin = 2),噩夢的開始,天知道我花了多久在思考這裡。我們先再看一次內層的迴圈。

for (let i = coin; i <= amount; i++) {
            dp[i] += dp[i - coin];
        }

可以知道我們硬幣 2 要從目標金額 2 (i = 2) 開始湊了。但為什麼是dp[i] += dp[i - coin]

先再重申一次 dp[i] 是儲存湊成 i 金額方法數的地方,所以 dp[2] 就是儲存湊成 2 的方法數的地方,再一次強調,免得待會打結。

好,現在來看一下下面這張圖,我用紅色和藍色分別標記了兩個 1,是什麼意思?是這樣的:

  • 紅色的 1:dp[2] 在第一次遍歷時,也就是 coin = 1 時所儲存的方法數,也就是 "1 + 1" 這個組合。
  • 藍色的 1:dp[2] 在第二次遍歷時,也就是 coin = 2 時所要更新儲存進去的方法數。我們知道也就是只取 2 這一個方法,但我們應該想成 "0 + 2" 這個組合,而我們有沒有湊成 0 的方法數?答案是有的,在一開始就定義了,也就是 1。
raw-image

我們接著看 dp[3]:

  • 紅色的 1:在第一次遍歷時儲存了一個方法,也就是 "1 + 1 + 1"。
  • 藍色的 1:到了第二次遍歷時,我們多出了 "1 + 2" 這個組合,而湊成 1 的方法數到目前為止是 1。
dp[3]

dp[3]

再一次啊,來看 dp[4]:

  • 紅色的 1:在第一次遍歷時儲存了只用 coin = 1 的方法,也就是 "1 + 1 + 1 + 1"。
  • 藍色的 2:哇!變成 2 了,怎麼不是 1 了?其實按照剛剛的邏輯來看,我們用 coin = 2 要湊 i = 4 時,會得到 "2 + 2" 這個組合,那我們前面已經存過截至目前為止所儲存可以湊出 2 的方法數有 2 個,也就是 coin = 1 時儲存的 "1 + 1" 和迴圈才剛剛跑過去沒多久的 "0 + 2"
dp[4]

dp[4]

所以到這裡可以知道dp[i] += dp[i - coin]這裡面dp[i]代入的是前一次遍歷更新後湊成 i 的方法數,dp[i - coin]代表著使用了一次這個硬幣後,我們還需要湊成剩餘金額 "i - coin" 的湊法數量,而這個數量我們已經在前面的迴圈中儲存在 dp 中了。

到這裡我們可以看到,每次代入的參數其實都是前一次遍歷和迴圈帶來的結果,這樣一層一層堆砌成最後的解答,動態規劃的概念這就出現了。

最後我們會得到下面這張圖,也就是此時 dp = [1, 1, 2, 2, 3, 4]。而 4 就是我們最終的解答。

raw-image

e04!真的搞了我好久,我要好好去學演算法了...



參考資料:

  1. 贾考博 LeetCode 518. Coin Change 2 - 这应该是hard
  2. LeetCode 518 Coins Change II解题分享 DP


留言
avatar-img
留言分享你的想法!
阿Han-avatar-img
2023/08/11
解題高手XD
Jeremy Ho-avatar-img
發文者
2023/08/12
阿Han 我是解題新手,跟前輩們比還有很多要學~
avatar-img
Jeremy Ho的沙龍
19會員
37內容數
這個專題用來存放我在學習網頁開發時的心得及知識。
Jeremy Ho的沙龍的其他內容
2023/12/03
從 leetcode 學資料結構堆疊 (stack)
Thumbnail
2023/12/03
從 leetcode 學資料結構堆疊 (stack)
Thumbnail
2023/10/04
SQL語法:JOIN 與交易
Thumbnail
2023/10/04
SQL語法:JOIN 與交易
Thumbnail
2023/10/03
SQL 基本篇 - CRUD、運算子、內建函式
Thumbnail
2023/10/03
SQL 基本篇 - CRUD、運算子、內建函式
Thumbnail
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
題目敘述 題目給定一棵二元樹,整棵樹剛好有n個節點 和 總共n枚金幣。 每個節點的值代表該節點初始擁有金幣的數量。 每回合可以給周圍的節點一枚金幣,請問最少需要幾回合才能讓所有節點恰好擁有一枚金幣? 原本的英文題目敘述
Thumbnail
題目敘述 題目給定一棵二元樹,整棵樹剛好有n個節點 和 總共n枚金幣。 每個節點的值代表該節點初始擁有金幣的數量。 每回合可以給周圍的節點一枚金幣,請問最少需要幾回合才能讓所有節點恰好擁有一枚金幣? 原本的英文題目敘述
Thumbnail
這題的題目會給我們一個輸入整數,要求我們判斷這個整數是否可以用2^k 的形式來表達 (二的冪)?
Thumbnail
這題的題目會給我們一個輸入整數,要求我們判斷這個整數是否可以用2^k 的形式來表達 (二的冪)?
Thumbnail
這題的題目會給我們一個輸入整數,要求我們判斷這個整數是否可以用4^k 的形式來表達?
Thumbnail
這題的題目會給我們一個輸入整數,要求我們判斷這個整數是否可以用4^k 的形式來表達?
Thumbnail
題目會給定我們一組十進位表示法的阿拉伯數字,要求我們把它轉換為對應的羅馬數字。
Thumbnail
題目會給定我們一組十進位表示法的阿拉伯數字,要求我們把它轉換為對應的羅馬數字。
Thumbnail
題目會給我們一個輸入陣列candidates,和一個目標值 target 問我們,從canditdates裡面重複挑選,可以湊出總和為target目標值的組合數有幾種? 在此,我們將使用找零錢II的DP模型和化簡的技巧來解題。
Thumbnail
題目會給我們一個輸入陣列candidates,和一個目標值 target 問我們,從canditdates裡面重複挑選,可以湊出總和為target目標值的組合數有幾種? 在此,我們將使用找零錢II的DP模型和化簡的技巧來解題。
Thumbnail
在經過比較簡單的入門題(Coin Change)之後, 來看進階一點的DP題目Coin Change II 整零錢的全部方法數。 不免俗,再次強調DP的解題框架,鞏固知識點。
Thumbnail
在經過比較簡單的入門題(Coin Change)之後, 來看進階一點的DP題目Coin Change II 整零錢的全部方法數。 不免俗,再次強調DP的解題框架,鞏固知識點。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News