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

閱讀時間約 13 分鐘

最近會試著寫一些統整類的文章,
幫助讀者、觀眾整理、吸收、複習已經學習到的演算法框架。


找零錢框架

在以前學過的題目中,我們已經學會了找零錢的抽象思考邏輯與框架,就是試著用每一種銅板去湊出n元(也就是找零錢的過程)


寫成虛擬碼或演算法,找零錢用了幾枚銅板可以這樣表達

# 銅板數目累加​
# n-coin 元 + coin這枚銅板,就可以湊出n元。
dp[ n ] = dp[ n- coin ] + 1


寫成虛擬碼或演算法,找零錢的方法數可以這樣表達

for coin in coins:
# 方法數累加​
# n-coin 元 + coin這枚銅板,就可以湊出n元。
dp[ n ] += dp[ n - coin ]


接下來,我們會用這個上面這兩種結構,貫穿一些同類型,有關聯的題目
(請讀者、或觀眾留意上面的這種DP結構,之後的解說會反覆出現)

最精簡找零 Coin Change I (原本這題的專門教學文章在這裡)

對於 Coin Change I 來說,我們要找的是最精簡的找零數目,也就是
用最少的銅板湊出n元,於是我們就用DP找零錢用了幾枚銅板的演算法來解。
就像下面看到的這樣:

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

# key: $value
# value: minimal coin change of $value
dp = defaultdict(lambda: math.inf)

# Base case
# $0 is reached by taking nothing
dp[0] = 0

# General case:
# Try to make change with current coin
# 請注意看,剛剛介紹的DP演算法框架就出現在這裡!
for coin in coins:
for value in range(coin, amount+1):
dp[value] = min(dp[value], dp[value-coin]+1 )


if dp[amount] == math.inf:
return -1

return dp[amount]

有沒有別的題目用到同樣的結構?

其實有喔,在Perfect Squares 這題就是。


最精簡找零 的衍伸變形 Perfect Squares



這題要求我們計算整數n的最精簡的完全平方數的化簡次數。

我們可以把n視為目標金額(要找開的對象),所有小於等於n的完全平方數視為題目供應的銅板陣列

如此一來,這題就被我們化簡到最精簡找零

於是我們就用DP找零錢用了幾枚銅板的演算法來解。就像下面看到的這樣:

class Solution:
def numSquares(self, n: int) -> int:

INF = sys.maxsize
dp = [ INF for _ in range(n+1) ]
dp[0] = 0

root = 1
square = root*root

# for each square number 1, 4, 9, 16, 25...
# 請注意看,剛剛介紹的DP演算法框架就出現在這裡!
while( square <= n ) :

# update dp value for number from square to n
for i in range(square, n+1) :

dp[i] = min( dp[i], dp[i-square]+1 )

# go to next square number
root += 1
square = root*root


return dp[n]

Perfect Squares 和上面那一題 Coin Change I 九成都很像!對吧~

只是改成特殊的銅板(都是完全平方數)而已,其他思考邏輯都相同



找零錢的方法總數(嚴格一點說,就是數學上的組合數) Coin Change II
(原本這題的專門教學文章在這裡)

對於 Coin Change II 來說,我們要找的是找零錢的方法總數,就是數學上的組合數(與次序無關)。

例如 $5 + $1 和 $1 + $5 會被視為一種而已(因為組合數不考慮順序)
這是實作上的細節,請特別留意

想清楚題目要問的
究竟是 組合數(不考慮順序),還是排列數(考慮順序),這兩者是有區別的。


於是我們就用DP找零錢的方法數的演算法來解。就像下面看到的這樣:

我們每次迭代時,外圈先固定用某一種銅板針對所有金額去找零錢確保同一種銅板不會再之後的找零錢過程中重複出現

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

# base case:
# amount 0's method count = 1 (by taking no coins)
dp = [1] + [ 0 for _ in range(amount)]

# make change with current coin, from small coin to large coin
# 請注意看,剛剛介紹的DP演算法框架就出現在這裡!
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
dp[small_amount] += dp[small_amount - cur_coin]

return dp[amount]

好,現在我們知道找零錢的組合數了。

那...假如別的題目要求我們列出找零錢的具體方法呢?


其實有,只是被出題者包裝過,用別的樣貌呈現,但本質還是相同的,

這題就是Combination Sum


找零錢的具體方法 Combination Sum


原本Coin Change II是計算有幾個組合數,
現在Combination Sum是改成紀錄組合的狀態,用同樣的手法更新即可


於是我們就用DP找零錢的方法數的演算法來紀錄組合的狀態。就像下面看到的這樣:

我們每次迭代時,外圈先固定用某一種銅板針對所以金額去找零錢確保同一種銅板不會再之後的找零錢過程中重複出現

class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:

dp = defaultdict(list)

## Base case:
# $0 is reached by taking nothing
dp[0] = [ [ ] ]

coins = candidates

## General cases:
# 請注意看,剛剛介紹的DP演算法框架就出現在這裡!
for coin in coins:
for amount in range(coin, target+1):

# satisfy $amount from ($amount-$coin) + $coin
for prev_coin_change in dp[ amount - coin ]:
dp[amount] += [ prev_coin_change + [coin] ]

return dp[ target ]

Combination Sum 和上面那一題 Coin Change II 九成都很像!對吧~

只是改成紀錄組合的狀態而已,其他思考邏輯都相同


那有沒有類似找零錢的題目,但是要考慮順序的呢?也就是要求我們計算排列數的?

其實有,只是被出題者包裝過,用別的樣貌呈現,但本質還是相同的,
這題就是Combination Sum IV

找零錢的方法排列數(嚴格說,就是數學上的排列數) Combination Sum IV



對於 Combination Sum IV 來說,
我們可以把target是為目標金額(要找開的對象),nums視為題目供應的銅板陣列
如此一來,這題就被我們化簡到找零錢問題。

由從題意和範例可以知道,這題把不同的順序視為不同的兩種。

例如 $5 + $1 和 $1 + $5 會被視為不同的兩種而已(因為排列數要考慮順序)
這是實作上的細節,請特別留意

想清楚題目要問的
究竟是 組合數(不考慮順序),還是排列數(考慮順序),這兩者是有區別的。


於是我們就用DP找零錢的方法數的演算法來解。就像下面看到的這樣:

我們每次迭代時,外圈反而先迭代所有金額內圈才迭代每一種銅板針對當下的金額去找零錢,允許同一種銅板在之後的找零錢過程中又重複出現

class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:

## Dictionary
# key: amount
# value: method count to make change up to specific amount
dp = defaultdict(int)

# $0 is reached by taking nothing, only one way to do so
dp[0] = 1

# For each value in range [1, target]
# 請注意看,剛剛介紹的DP演算法框架就出現在這裡!
for value in range(1, target+1):

# Try each possible coin
for coin in nums:

# Coin is too big, impossible to make change
if coin > value: continue

# Make change with smaller coin
# $value = $(value-coin) + $coin
dp[value] += dp[value-coin]

# Total method count to make change up to $target
return dp[target]


Combination Sum IV 和上面那一題 Coin Change II 九成都很像!對吧~

只是改成紀錄排列數(考慮順序)而已,其他思考邏輯都相同


細微的差異就是我們用銅板放在內層迴圈還是外層迴圈
來控制同一種銅板在之後可不可以重複出現


結語

好,今天一口氣介紹了最精華的部分,

通用的Coin Change 找零錢模型的框架,還有相關的衍伸變化題與演算法化簡流程,

希望能幫助讀者、觀眾徹底理解它的原理,
並且能夠舉一反三,洞察其背後的本質和了解相關的應用領域!


感謝收看囉! 我們下篇文章再見~

82會員
417Content count
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
發表第一個留言支持創作者!
題目敘述 給定一個正整數n,請找出最少用幾個完全平方數,可以讓他們的總和為n? 例如 n=12,最少用3個完全平方數就可讓他們的總和為n,因為12 = 4 + 4 + 4 題目的原文敘述 測試範例 Example 1: Input: n = 12 Output: 3 Explanat
題目敘述 題目會給我們一個輸入陣列nums,和一個指定的k值。 請問,在輸入陣列nums中,有幾個子陣列的元素總合恰好為k ? 例如: nums = [1,2,3], k = 3 則有兩個子陣列的元素總合為3,分別是[1,2] 和 [3] 如果是第一次聽到或接觸前綴和prefix的同學
題目敘述 題目會給定我們一個字串s,和一組字庫wordDict。 問我們能不能透過字串串接的方式,從字庫裡面的字拼成原本的字串s? 可以的話,返回True。 無解的話,返回False。 註: 題目還允許重複使用字庫裡面的字去串接。
題目敘述 題目會給定一個指定高度和寬的方格版,還有一顆小球的起始位置,和最大移動步數。 小球每一步可以選擇向上、下、左、右移動一格,請問小球能走到方格版界外的路徑方法數總共有幾種? 方法數可能很大,題目要求,最後回傳答案時,先對10^9+7做除法取餘數再回傳。 題目的原文敘述 約束條件
題目敘述 題目會給我們一個二維陣列matrix,分別代表每個格子的成本,請問我們從最頂端到底部的下墜路徑的最小成本總和是多少? 每次下墜到下一排的時候,可以有三種選擇: 1.往左下角移動。 2.往正下方移動。 3.往右下角移動。 題目的原文敘述 測試範例 Example 1:
題目敘述 題目會告訴我們一組英文和數字之間的轉換編碼規則,還有一個輸入字串s,問我總共有多少合法的解碼方式? 要特別留意,輸入字串可能包含有leading zero,導致無法解碼。 轉換規則如下: A <-> 1 B <-> 2 C <-> 3 ... Z <-> 26 詳細的題
題目敘述 給定一個正整數n,請找出最少用幾個完全平方數,可以讓他們的總和為n? 例如 n=12,最少用3個完全平方數就可讓他們的總和為n,因為12 = 4 + 4 + 4 題目的原文敘述 測試範例 Example 1: Input: n = 12 Output: 3 Explanat
題目敘述 題目會給我們一個輸入陣列nums,和一個指定的k值。 請問,在輸入陣列nums中,有幾個子陣列的元素總合恰好為k ? 例如: nums = [1,2,3], k = 3 則有兩個子陣列的元素總合為3,分別是[1,2] 和 [3] 如果是第一次聽到或接觸前綴和prefix的同學
題目敘述 題目會給定我們一個字串s,和一組字庫wordDict。 問我們能不能透過字串串接的方式,從字庫裡面的字拼成原本的字串s? 可以的話,返回True。 無解的話,返回False。 註: 題目還允許重複使用字庫裡面的字去串接。
題目敘述 題目會給定一個指定高度和寬的方格版,還有一顆小球的起始位置,和最大移動步數。 小球每一步可以選擇向上、下、左、右移動一格,請問小球能走到方格版界外的路徑方法數總共有幾種? 方法數可能很大,題目要求,最後回傳答案時,先對10^9+7做除法取餘數再回傳。 題目的原文敘述 約束條件
題目敘述 題目會給我們一個二維陣列matrix,分別代表每個格子的成本,請問我們從最頂端到底部的下墜路徑的最小成本總和是多少? 每次下墜到下一排的時候,可以有三種選擇: 1.往左下角移動。 2.往正下方移動。 3.往右下角移動。 題目的原文敘述 測試範例 Example 1:
題目敘述 題目會告訴我們一組英文和數字之間的轉換編碼規則,還有一個輸入字串s,問我總共有多少合法的解碼方式? 要特別留意,輸入字串可能包含有leading zero,導致無法解碼。 轉換規則如下: A <-> 1 B <-> 2 C <-> 3 ... Z <-> 26 詳細的題
你可能也想看
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
藍白合破局後,各黨也陸續公布其總統候選人副手。而國民黨侯友宜與趙少康組成的「侯康配」民調卻讓人難以信服,看看兼任中廣董事長以及總經理的趙少康,再看看國民黨水漲船高的民調,引起外界質疑民調淪為政媒操作下的產物。
Thumbnail
2023年4月5日至8日,❙法國❙ 總統 ❙馬克龍❙ 對 ❙中華人民共和國❙ 進行國事訪問,期間有關應該避免陷入 ❙中美❙ 在 ❙台灣❙ 問題上的對抗的言論在西方政界引起軒然大波。 準確地說,❙馬克龍❙ 的 ❙歐洲❙「戰略自主」論調並非在國事訪問期間發表的,而是在國事訪問後,在飛回 —— 途經廣州
Thumbnail
話說商鞅被車裂後,秦惠王恨他歸恨他,但卻很理智,商鞅的一系列方針政策繼續沿用。 因為他發現商鞅打造的這臺國家機器太好用了,短短二十年的時間,秦國從被看不起的西戎小國到被周天子官方封為西部大總管,這種感覺太美妙了。 一碼歸一碼的處理方法,顯示出了秦惠王的政治水平。 政治,是一種需要極高理性的遊戲,還是
Thumbnail
在台北市中心街弄中有許多藝術機構,這些藝術機構不論是畫廊、美術館、藝術教室、藝文空間、博物館等多種形式存在。從這些藝術機構更扮演著社會大眾與藝術接觸機會。長流美術館算是台灣藝術機構之先進機構,憑藉著長流機構背景讓藝術深入社會大眾心中。 長流美術館相關資訊:: 地址: 台北市大安區仁愛路二段63號B1
Thumbnail
縱貫式中介模型(Longitudinal Mediation Model)是研究隨著時間的改變,變數X如何通過中介變數M影響變數Y的統計模型。它是長期觀察和分析數據的有用工具,可以揭示X和Y之間的關係以及中介變數M在這個關係中扮演的角色。本文將介紹縱貫式中介模型Mplus操作
Thumbnail
唉!這陣子我太常在公司嘆氣,我無法要求別人一定要進步,但每個人的職位就要做好該職位的工作內容,不是嗎? 有些人並不是這樣子想,領多少薪水做多少事是應該的,其實大家都是在工作賺錢,想想你的職位是什麼,該做就要做,不是應該的嗎? 客服工作不就是要熟悉系統,去了解客戶的問題點在哪,進而回答客戶的問題,這不
Thumbnail
時隔多年,看到網飛(Netflix)將這部電影購入旗下著實是一種驚喜! 一個外貌看似九歲其實實際年齡早已三十有餘的偽蘿莉處心積慮機關算盡搶奪當家女主人大位的奮鬥史(無誤),我先把孤兒怨劇情的主體告訴各位,因為這部片的梗其實不難猜而且也不新鮮,比較讓我覺得有趣的是孤兒怨除了有鮮血、屍體、嚇人橋段之外,
Thumbnail
《NBA 2K20》發售以來應該不少玩家發現了一個奇妙的現象,許多充滿權威性的評分媒體都給予了中高以上的分數,但玩家這頭卻連 1 分都捨不得給。當然,我們無法得知或是去揣測那些給高分媒體是不是真的覺得遊戲好玩,至少在玩家們一致性的評論中,可以得知這款遊戲確實出了某種問題。
Thumbnail
歷史記載,所謂「合縱」又稱「合從」也就是聯合幾個較弱的國家對抗強大的秦國,巧合的是 alliance ㄧ字竟然也可能「alliance = a.ll.i.an.ce = 合.人人.以.anti.cina = 合.从.以.反.秦 = 合.從.以.反.秦 = 合從以反秦 = 合縱以反秦」或 ......
Thumbnail
重點摘要: 1.9 月降息 2 碼、進一步暗示年內還有 50 bp 降息 2.SEP 上修失業率預期,但快速的降息速率將有助失業率觸頂 3.未來幾個月經濟數據將繼續轉弱,經濟復甦的時點或是 1Q25 季底附近
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
Thumbnail
藍白合破局後,各黨也陸續公布其總統候選人副手。而國民黨侯友宜與趙少康組成的「侯康配」民調卻讓人難以信服,看看兼任中廣董事長以及總經理的趙少康,再看看國民黨水漲船高的民調,引起外界質疑民調淪為政媒操作下的產物。
Thumbnail
2023年4月5日至8日,❙法國❙ 總統 ❙馬克龍❙ 對 ❙中華人民共和國❙ 進行國事訪問,期間有關應該避免陷入 ❙中美❙ 在 ❙台灣❙ 問題上的對抗的言論在西方政界引起軒然大波。 準確地說,❙馬克龍❙ 的 ❙歐洲❙「戰略自主」論調並非在國事訪問期間發表的,而是在國事訪問後,在飛回 —— 途經廣州
Thumbnail
話說商鞅被車裂後,秦惠王恨他歸恨他,但卻很理智,商鞅的一系列方針政策繼續沿用。 因為他發現商鞅打造的這臺國家機器太好用了,短短二十年的時間,秦國從被看不起的西戎小國到被周天子官方封為西部大總管,這種感覺太美妙了。 一碼歸一碼的處理方法,顯示出了秦惠王的政治水平。 政治,是一種需要極高理性的遊戲,還是
Thumbnail
在台北市中心街弄中有許多藝術機構,這些藝術機構不論是畫廊、美術館、藝術教室、藝文空間、博物館等多種形式存在。從這些藝術機構更扮演著社會大眾與藝術接觸機會。長流美術館算是台灣藝術機構之先進機構,憑藉著長流機構背景讓藝術深入社會大眾心中。 長流美術館相關資訊:: 地址: 台北市大安區仁愛路二段63號B1
Thumbnail
縱貫式中介模型(Longitudinal Mediation Model)是研究隨著時間的改變,變數X如何通過中介變數M影響變數Y的統計模型。它是長期觀察和分析數據的有用工具,可以揭示X和Y之間的關係以及中介變數M在這個關係中扮演的角色。本文將介紹縱貫式中介模型Mplus操作
Thumbnail
唉!這陣子我太常在公司嘆氣,我無法要求別人一定要進步,但每個人的職位就要做好該職位的工作內容,不是嗎? 有些人並不是這樣子想,領多少薪水做多少事是應該的,其實大家都是在工作賺錢,想想你的職位是什麼,該做就要做,不是應該的嗎? 客服工作不就是要熟悉系統,去了解客戶的問題點在哪,進而回答客戶的問題,這不
Thumbnail
時隔多年,看到網飛(Netflix)將這部電影購入旗下著實是一種驚喜! 一個外貌看似九歲其實實際年齡早已三十有餘的偽蘿莉處心積慮機關算盡搶奪當家女主人大位的奮鬥史(無誤),我先把孤兒怨劇情的主體告訴各位,因為這部片的梗其實不難猜而且也不新鮮,比較讓我覺得有趣的是孤兒怨除了有鮮血、屍體、嚇人橋段之外,
Thumbnail
《NBA 2K20》發售以來應該不少玩家發現了一個奇妙的現象,許多充滿權威性的評分媒體都給予了中高以上的分數,但玩家這頭卻連 1 分都捨不得給。當然,我們無法得知或是去揣測那些給高分媒體是不是真的覺得遊戲好玩,至少在玩家們一致性的評論中,可以得知這款遊戲確實出了某種問題。
Thumbnail
歷史記載,所謂「合縱」又稱「合從」也就是聯合幾個較弱的國家對抗強大的秦國,巧合的是 alliance ㄧ字竟然也可能「alliance = a.ll.i.an.ce = 合.人人.以.anti.cina = 合.从.以.反.秦 = 合.從.以.反.秦 = 合從以反秦 = 合縱以反秦」或 ......