簡體   English   中英

理解Python中的一個LeetCode遞歸問題(322幣找零)

[英]Understanding a LeetCode recursion problem in Python (322 Coin Change)

Leetcode 問題: https://leetcode.com/problems/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

這是我對下面代碼的思考過程。

  1. 不需要反向我只是把它放在那里讓它在調試器中更快
  2. 我將設置一個回溯模板並遍歷所有索引嘗試每個選項
  3. 如果我匹配我返回的答案(這可能是錯誤的原因,因為我從不彈出總金額,並且可能有另一個選擇更少硬幣的選項)
  4. 我一直在調用回溯,試圖增加同一個硬幣,直到它不起作用
  5. 如果失敗,我會調用另一個回溯 function 遞增索引以嘗試達到最終結果

來自更有經驗的人:您將如何解決這個問題/識別模式? 我最初的嘗試是貪心算法,但我很快發現那行不通。

也許我應該研究更多自上而下自下而上的方法,但任何關於如何繼續變得更好或實踐的建議將不勝感激。 我花了很多時間在調試器上試圖理解這些問題。 我一直想放棄,但我知道這不是一種選擇,而是學習曲線的一部分。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM