[英]Understanding a LeetCode recursion problem in Python (322 Coin Change)
322硬幣變化:
你得到一個代表不同面額硬幣的 integer 數組硬幣和一個代表總金額的 integer 數量。
返回您需要的最少數量的硬幣來彌補該金額。 如果該金額不能由任何硬幣組合彌補,則返回-1。
您可以假設您擁有無限數量的每種硬幣。
Example 1:
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3
Output: -1
Example 3:
Input: coins = [1], amount = 0
Output: 0
Example 4:
Input: coins = [1,4,5], amount = 8
Output: 2
Explanation: 8 = 4 + 4
因此,我一直在與遞歸作斗爭,並一直在練習 DFS、BFS、Perms、Combos、子集等各種不同類型的問題,並取得了一些進展,但並不是我想要面試的地方。
我知道這個問題可以用 DP 來解決,但在繼續這個概念之前,我想先用 DFS 來解決它來理解這個問題。 我找不到有關解決方案的 DFS 示例。
所以這是我的第一次嘗試,我一直在失敗一些案例,例如[186,419,83,408], 6249
。
這是我對下面代碼的思考過程。
來自更有經驗的人:您將如何解決這個問題/識別模式? 我最初的嘗試是貪心算法,但我很快發現那行不通。
也許我應該研究更多自上而下自下而上的方法,但任何關於如何繼續變得更好或實踐的建議將不勝感激。 我花了很多時間在調試器上試圖理解這些問題。 我一直想放棄,但我知道這不是一種選擇,而是學習曲線的一部分。
def coinChange(self, coins: List[int], amount: int) -> int:
coins = coins[::-1]
minCoin = inf
def backtrack(i,total,count):
nonlocal minCoin
if total == amount:
minCoin = min(minCoin,count)
return
if total + coins[i] <= amount:
count += 1
backtrack(i,total + coins[i],count)
if i + 1 < len(coins):
backtrack(i+1,total,count)
for i in range(len(coins)):
backtrack(i,0,0)
return minCoin if minCoin != inf else -1
我認為“貪婪”是正確的做法。 首先假設您需要最大的硬幣,然后解決剩下的子問題。 如果失敗,請減少最大硬幣的數量並重試。
coins = [186,419,83,408]
coins.sort( reverse=1 )
tgt = 6249
def change( n, tgt, coins ):
if not coins:
return None
for m in range(tgt // coins[0],-1,-1):
tgt1 = tgt - m * coins[0]
if not tgt1:
print(n, m, "Answer!")
return [m]
chk = change( n+1, tgt1, coins[1:] )
if chk:
print(n, m, "Answer!")
return [m] + chk
print(change( 0, tgt, coins ))
Output:
3 13 Answer!
2 1 Answer!
1 4 Answer!
0 8 Answer!
[8, 4, 1, 13]
我認為您的代碼由於傳遞了索引參數“i”而失敗。 問題陳述說:
您可以假設您擁有無限數量的每種硬幣。
這意味着如果total + coins[i] <= amount
你必須為所有硬幣做一個 for 循環。 在您的代碼中,您必須從第 0 個索引開始,但您從同一索引開始回溯。
在遞歸問題中,能夠更容易地可視化決策樹。
對於 nums 中的每個 num,您遞歸地對新目標target-num
進行新調用。 如果到達葉節點,則返回空數組 []。 當您拉回根目錄時,將 num 添加到每個級別的數組中。 在進行遞歸調用時,您還應該在 memory 中跟蹤迄今為止的最短路徑,如果返回有效的結果數組,請將結果與迄今為止的最短數組進行比較並更新最短數組
from typing import List
class Solution:
def coinChange(self, nums: List[int], target: int) -> int:
def dfs(target, memo={}):
# without memoization it wont pass
if target in memo:
return memo[target]
# base case changes depending on your logic
if target == 0:
return []
if target < 0:
return None
shortest_combination = None
for num in nums:
remainder = target - num
# this is where the decision tree is built
result = dfs(remainder)
# make sure not if result because result might be [] which yields to False
if result != None:
# combination = result+[num]
combination = [*result, num]
# when we get the first result, we assign shortest_combination to that result.
# so shortest_combination == None this will be true only once
if shortest_combination == None or len(combination) < len(shortest_combination):
shortest_combination = combination
memo[target] = shortest_combination
return shortest_combination
return -1 if dfs(target) == None else len(dfs(target))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.