DP動態規劃 深入淺出 以Coin change II 找零方法數 為例

小松鼠-avatar-img
發佈於演算法題目解析 個房間
更新 發佈閱讀 10 分鐘


vocus|新世代的創作平台

如同這個Dynamic programming 深入淺出系列的開始,在經過比較簡單的入門題(Coin Change)之後,來看進階一點的DP題目Coin Change II


不免俗,再次強調DP的解題框架,鞏固知識點。

Dynamic programming本質是透過遞迴關係式,去解決一個大規模的問題,而這個大規模的問題又可以被分解為較小規模的子問題,而且子問題往往彼此重複


Dynamic programming的解題框架可分為三大步驟
1. 定義狀態 [我在哪裡]
2. 定義狀態轉移關係式(通則) [我從哪裡來] => [答案從哪裡推導而來]
3. 釐清初始狀態(也可以說是遞迴的終止條件) [第一步怎麼走,怎麼出發的]

題目敘述  Coin Change II

給定銅板陣列coins,和目標金額amount。
要求我們計算找零組合方法總數


測試範例

Example 1:

5 元總共有4種找零方法,分別是

5元銅板一枚

2元銅板兩枚+1元銅板一枚

2元銅板兩枚+1元銅板三枚

1元銅板五枚

Input: amount = 5, coins = [1,2,5]
Output: 4
Explanation: there are four ways to make up the amount:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

Example 2:

Input: amount = 3, coins = [2]
Output: 0
Explanation: the amount of 3 cannot be made up just with coins of 2.

Example 3:

Input: amount = 10, coins = [10]
Output: 1

我們還是先走過一遍解題框架可分為三大步驟,藉此鞏固解題基礎。

1. 定義狀態 [我在哪裡]

這題如果寫過Coin change的人,可能會有一個直接的想法:

Easy, 這題就是前一提的變形,用類似的定義,改成相加就好。

乍看沒問題,但是我們是著走過一個小例子,看看會遇到什麼情況

定義DP[n] = n元零錢找零組合數目。

假設只有兩種銅板$1和$2,問: 找開3元有幾種組合數

DP[0] = 1 顯然0元只有一種找零組合數: 所有銅板都不拿

DP[1] = 1 顯然1元只有一種找零組合數: $1銅板一枚

DP[2] = DP[2-1] + DP[2–2] = DP[1] + DP[0] = 1 + 1 = 2

2元有兩種找零組合數: $1銅板兩枚 或 $2銅板一枚

恩…so far so good 看起來沒問題,但真的是如此嗎?


繼續看下去,看n=3的時候會發生什麼事

DP[3] = DP[3–1] + DP[3–2] = DP[2] + DP[1] = 2 + 1 = 3

這個錯的DP演算法告訴我們有3元有三種找零組合數

但是,其實3元只有兩種找零組合數:


第一種方法 $1銅板3枚 或
第二種方法 $1銅板1枚和 $2銅板1枚


那為什麼上面的DP算法會出現三種呢?

因為上面那種定義無形中已經考慮排列,

但是題目只要求組合數目,所以出現了重複計算的情狀。


DP[3]

= DP[3 - 1] (註: 這個-1代表用$1銅板一枚來湊最後一步) +

DP[3 - 2] (註:這個-2代表用$2銅板一枚來湊最後一步)

= DP[2]+ DP[1]

打開來看,看裡面發生了什麼事

DP[2] = $1銅板兩枚 或 $2銅板一枚 (+ $1銅板一枚來湊最後一步)

=> “$1銅板三枚” 或 “$2銅板一枚 + $1銅板1枚

DP[1] = $1銅板一枚 (+用$2銅板一枚來湊最後一步)

=> “$1銅板一枚 + $2銅板一枚


仔細看標粗體的地方,“$2銅板一枚 + $1銅板1枚” 和 “$1銅板一枚 + $2銅板一枚”其實是同一種組合,在DP[2]這條路徑被計入一次,在DP[1]這條路徑又被記入一次,重複了!

所以原本這個定義是錯的,不能使用


那該怎麼辦呢?


其實,DP也不限定只能一維,我們可以引入一個新的維度,代表銅板的index,一但考慮過,就前往下一個銅板的index,避免重複計算

DP[ coinIdx, n]: 代表考慮當下這個銅板coins[coinIdx],湊出n元的組合數


2. 定義狀態轉移關係式(通則)
[我從哪裡來] => [答案從哪裡推導而來]

這裡題目也沒給,不過沒關係,我們可以試者推倒看看。

用剛剛的小範例幫助我們思考

Input: amount = 3 coins =[1,2]
Output: 2

3元的找零組合數

使用兩元銅板的3元的找零組合數 + 不使用兩元銅板的3元的找零組合數

再往下展開

使用兩元銅板使用一元銅板的3元的找零組合數 +

使用兩元銅板不使用一元銅板的3元的找零組合數 +

不使用兩元銅板使用一元銅板的3元的找零組合數 +

不使用兩元銅板不使用一元銅板的3元的找零組合數

$2銅板一枚 $1銅板1枚 +

無法找開 +

$1銅板3枚 +

無法找開


所以,總共就是兩種:

$2銅板一枚 $1銅板1枚, 或 $1銅板3枚 去找開3塊錢

輸出為2

推廣到通則就是

DP(coinIdx, n )

= DP( coinIdx-1, n ) + DP( coinIdx, n — coins[coinIdx] )

不使用coins[coinIdx]元銅板的n元的找零組合數 + 使用coins[coinIdx]元銅板的n元的找零組合數


3. 釐清初始狀態(終止條件)
[第一步怎麼走,怎麼出發的]

終止條件滿明顯的,

就是n=0 (0塊錢),和n<0負數(因為負的幣值無法找零)的狀態。

0塊錢找零只有一種方法,就是不拿任何一枚銅板,return 1。


負的幣值無法找零,找零組合數為0,return 0


另外,負的coinIdx,代表沒有提供零錢去找零,

很顯然,沒有提供零錢也無法找零,找零組合數也為0,return 0


到這裡,已經填滿解題框架的所有內容,接著我們把它轉成程式碼,

這裡以Python作為示範


程式碼 DP動態規劃

class Solution:
 def change(self, amount: int, coins: List[int]) -> int:

  table = {}

  def dp( coinIdx, n ):

   if n == 0:
    # base case
    # Change for $0, only one way to do so by taking nothing
    return 1

   if (coinIdx < 0) or (n < 0):
    # base cases
    # Cannot make change without valid coins
    # Cannot make change to negative values
    return 0

   if (coinIdx, n) in table:
    # look-up table
    return table[ (coinIdx, n) ]

   # general cases
   table[ (coinIdx, n) ] = dp( coinIdx-1, n ) + dp( coinIdx, n - coins[coinIdx] )
   return table[ (coinIdx, n) ]

  # ---------------------------------

  return dp( len(coins)-1, amount)

複雜度分析

時間複雜度:O( c * n )

零錢本身一個維度,amount被找開的金額本身又是另一個維度。


空間複雜度:O( c * n )

零錢本身一個維度,amount被找開的金額本身又是另一個維度。

DP table 所耗費空間剛好就是一張二維的表格,O( c * n )


等價的迭代寫法(Iterative implementation)

輔助思考的圖解範例

vocus|新世代的創作平台
class Solution:
 def change(self, amount: int, coins: List[int]) -> int:

  # base case:
  # amount 0's method count = 1 (by taking no coins)
  change_method_count = [1] + [ 0 for _ in range(amount)]
  
  # make change with current coin, from small coin to large coin
  for cur_coin in coins:
   
   # update change method count from small amount to large amount
   for small_amount in range(cur_coin, amount+1):
    
    # current small amount can make changed with current coin
    change_method_count[small_amount] += change_method_count[small_amount - cur_coin]
    
  return change_method_count[amount]

複雜度分析

時間複雜度:O( c * n )

零錢本身一個維度,amount被找開的金額本身又是另一個維度。


空間複雜度:O( n )

amount被找開的金額本身是一個維度。

change_method_count 所耗費空間剛好就是一張一維的表格,O( n )


關鍵知識點 找零錢DP框架

強烈建議跟著複習相關的Coin Change I演算法框架統整:

合縱連橫: 找零錢的DP框架_理解背後的本質

觸類旁通: 用 DFS回溯法框架 解 組合數之和 Combination sum 全系列題。

去鞏固知識點,強化理解與認識、加深印象。


Reference

[1] Python/JS/Go/C++ O(cn) DP // Unbounded Knapsack [w/ Visualization]


回到DP特訓班目錄 和 學習路徑

留言
avatar-img
小松鼠的演算法樂園
99會員
428內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
2024/09/13
給定一個整數陣列arr,和一串區間XOR請求queries。 請計算queries所請求的區間XOR值,並且以陣列的形式返回答案。
Thumbnail
2024/09/13
給定一個整數陣列arr,和一串區間XOR請求queries。 請計算queries所請求的區間XOR值,並且以陣列的形式返回答案。
Thumbnail
2024/08/27
Path with Maximum Probability 題目給定一個無向圖(雙向移動皆可), 提供每條邊的起終點,和每條邊對應的通過時的成功機率。 請問從起點start走到終點end的最高成功機率是多少? 如果完全沒有路徑可以抵達,則返回0。
Thumbnail
2024/08/27
Path with Maximum Probability 題目給定一個無向圖(雙向移動皆可), 提供每條邊的起終點,和每條邊對應的通過時的成功機率。 請問從起點start走到終點end的最高成功機率是多少? 如果完全沒有路徑可以抵達,則返回0。
Thumbnail
2024/08/21
題目敘述 664. Strange Printer 有一台奇怪的印表機, 每次操作只能連續印同樣的字母,但是列印的長度可以自由控制。 而且,印刷的時候,可以蓋過去舊的字元。 (這邊當然不合常理,讀者可以理解成塗了立可帶再蓋過去的情境) 給定一個輸入字串s,請問最少需要幾次操作,才能印出字串s?
Thumbnail
2024/08/21
題目敘述 664. Strange Printer 有一台奇怪的印表機, 每次操作只能連續印同樣的字母,但是列印的長度可以自由控制。 而且,印刷的時候,可以蓋過去舊的字元。 (這邊當然不合常理,讀者可以理解成塗了立可帶再蓋過去的情境) 給定一個輸入字串s,請問最少需要幾次操作,才能印出字串s?
Thumbnail
看更多
你可能也想看
Thumbnail
這題乍看之下是新題目,但仔細一想, 其實只是前面介紹過的費式數列的小變形而已,解題思想基本不變。 題目說每次可以爬一階樓梯或兩階樓梯,問爬到n階的方法數是多少。
Thumbnail
這題乍看之下是新題目,但仔細一想, 其實只是前面介紹過的費式數列的小變形而已,解題思想基本不變。 題目說每次可以爬一階樓梯或兩階樓梯,問爬到n階的方法數是多少。
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
背景:從冷門配角到市場主線,算力與電力被重新定價   小P從2008進入股市,每一個時期的投資亮點都不同,記得2009蘋果手機剛上市,當時蘋果只要在媒體上提到哪一間供應鏈,隔天股價就有驚人的表現,當時光學鏡頭非常熱門,因為手機第一次搭上鏡頭可以拍照,也造就傳統相機廠的殞落,如今手機已經全面普及,題
Thumbnail
如同這個Dynamic programming 深入淺出系列的開始, 在經過比較簡單的入門題(Coin Change)之後, 來看比較進階的二維DP題目Unique Path
Thumbnail
如同這個Dynamic programming 深入淺出系列的開始, 在經過比較簡單的入門題(Coin Change)之後, 來看比較進階的二維DP題目Unique Path
Thumbnail
最近會試著寫一些統整類的文章, 幫助讀者、觀眾整理、吸收、複習已經學習到的演算法框架。 找零錢框架 在以前學過的題目中,我們已經學會了考零錢的抽象思考邏輯與框架,就是試著用每一種銅板去湊出n元(也就是找零錢的過程) 寫成虛擬碼或演算法,找零錢用了幾枚銅板可以這樣表達 # 銅板數目累加​
Thumbnail
最近會試著寫一些統整類的文章, 幫助讀者、觀眾整理、吸收、複習已經學習到的演算法框架。 找零錢框架 在以前學過的題目中,我們已經學會了考零錢的抽象思考邏輯與框架,就是試著用每一種銅板去湊出n元(也就是找零錢的過程) 寫成虛擬碼或演算法,找零錢用了幾枚銅板可以這樣表達 # 銅板數目累加​
Thumbnail
深入淺出,從最基本的 費式數列, 一探動態規劃的奧秘與精隨。
Thumbnail
深入淺出,從最基本的 費式數列, 一探動態規劃的奧秘與精隨。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
本文分析導演巴里・柯斯基(Barrie Kosky)如何運用極簡的舞臺配置,將布萊希特(Bertolt Brecht)的「疏離效果」轉化為視覺奇觀與黑色幽默,探討《三便士歌劇》在當代劇場中的新詮釋,並藉由舞臺、燈光、服裝、音樂等多方面,分析該作如何在保留批判核心的同時,觸及觀眾的觀看位置與人性幽微。
Thumbnail
在學習過比較基本的DP模型 費式數列、爬樓梯、找零錢...等之後, 來看一個比較進階而且實用的DP模型,前綴和(Prefix sum), 可以再加以延伸推廣,來計算 區間和(Range Sum)。
Thumbnail
在學習過比較基本的DP模型 費式數列、爬樓梯、找零錢...等之後, 來看一個比較進階而且實用的DP模型,前綴和(Prefix sum), 可以再加以延伸推廣,來計算 區間和(Range Sum)。
Thumbnail
這題算是路徑計數類的DP衍伸題(路徑數、方法數、組合數...等等這種枚舉類的題目,第一時間切入除了想到DFS+回溯法之外,也可以留意DP動態規劃解題的可能性) 題目會給我們一個指定長度為arrLen的陣列,起點從index=0開始出發,每次移動可以往左移一格,往右移一格,或是留在原地不
Thumbnail
這題算是路徑計數類的DP衍伸題(路徑數、方法數、組合數...等等這種枚舉類的題目,第一時間切入除了想到DFS+回溯法之外,也可以留意DP動態規劃解題的可能性) 題目會給我們一個指定長度為arrLen的陣列,起點從index=0開始出發,每次移動可以往左移一格,往右移一格,或是留在原地不
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
5 月將於臺北表演藝術中心映演的「2026 北藝嚴選」《海妲・蓋柏樂》,由臺灣劇團「晃晃跨幅町」製作,本文將以從舞台符號、聲音與表演調度切入,討論海妲・蓋柏樂在父權社會結構下的困境,並結合榮格心理學與馮.法蘭茲對「阿尼姆斯」與「永恆少年」原型的分析,理解女人何以走向精神性的操控、毀滅與死亡。
Thumbnail
題目會給我們一個輸入陣列candidates,和一個目標值 target 問我們,從canditdates裡面重複挑選,可以湊出總和為target目標值的組合數有幾種? 在此,我們將使用找零錢II的DP模型和化簡的技巧來解題。
Thumbnail
題目會給我們一個輸入陣列candidates,和一個目標值 target 問我們,從canditdates裡面重複挑選,可以湊出總和為target目標值的組合數有幾種? 在此,我們將使用找零錢II的DP模型和化簡的技巧來解題。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
這是一場修復文化與重建精神的儀式,觀眾不需要完全看懂《遊林驚夢:巧遇Hagay》,但你能感受心與土地團聚的渴望,也不急著在此處釐清或定義什麼,但你的在場感受,就是一條線索,關於如何找著自己的路徑、自己的聲音。
Thumbnail
在經過比較簡單的入門題(Coin Change)之後, 來看進階一點的DP題目Coin Change II 整零錢的全部方法數。 不免俗,再次強調DP的解題框架,鞏固知識點。
Thumbnail
在經過比較簡單的入門題(Coin Change)之後, 來看進階一點的DP題目Coin Change II 整零錢的全部方法數。 不免俗,再次強調DP的解題框架,鞏固知識點。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News