【问题标题】:Implementing minimal coin amount for change with memoization?通过记忆实现最小的硬币数量以进行更改?
【发布时间】:2021-02-10 08:33:40
【问题描述】:

我正在练习动态编程的概念(递归不是我的强项)。我想知道如何改进我的代码,以避免堆栈溢出。

有什么帮助,谢谢!

def coinFlipping(n):
    """
    For n amount of change, return the minimal amount of currency in coins.

    Top-Down Approach (Memoization): Memo dictionary stores already solved
    subproblems to reuse and avoid recomputing. It's essentially recursion 
    but optimized to avoid recomputing results. 
    """
    COINS = {
        "penny": 0.01,
        "nickel": 0.05,
        "dime": 0.10,
        "quarter": 0.25,
        "dollar": 1.00
    }

    memo = {}

    def __coinFlipping(n):

        if n not in memo:
            # Base case (if n is equal to 0.01, 0.05, 0.10, 0.25..)
            if n in COINS.values():
                memo[n] = 1
            else:
                results = []
                coins = (coin for coin in COINS.values() if coin < n)
                for coin in coins:
                    results.append(__coinFlipping(n - coin))
                memo[n] = 1 + min(results)
        else:
            return memo[n]         
    __coinFlipping(n)
    print(memo[n])

coinFlipping(10)

我得到以下错误:

File "/mnt/d/programs/algorithms/dynamicProgramming.py", line 45, in __coinFlipping
    results.append(__coinFlipping(n - coin))
  File "/mnt/d/programs/algorithms/dynamicProgramming.py", line 45, in __coinFlipping
    results.append(__coinFlipping(n - coin))
  File "/mnt/d/programs/algorithms/dynamicProgramming.py", line 45, in __coinFlipping
    results.append(__coinFlipping(n - coin))
  [Previous line repeated 993 more times]
  File "/mnt/d/programs/algorithms/dynamicProgramming.py", line 44, in __coinFlipping
    for coin in coins:
  File "/mnt/d/programs/algorithms/dynamicProgramming.py", line 43, in <genexpr>
    coins = (coin for coin in COINS.values() if coin < n)
RecursionError: maximum recursion depth exceeded in comparison

【问题讨论】:

  • 嗯,这样的闭包是一种记忆方法(这回答了标题中的“问题”——确保标题与实际问题相关)。除了,修复 Too Much Recursion 问题。
  • 也就是说,这里使用浮点值是有问题的,因为这些值的精度有限。将 0.05 视为 5、将 0.25 视为 25 等将是有益的。
  • 写入浮点精度,这是false (!!!),例如:0.01 + 0.01 + 0.10 == 0.12。可能还有其他逻辑错误,没看——需要调试细节和重点,尤其是在标题中。
  • __coinFlipping 在缓存未命中时不返回任何内容。解决方法可能是删除 else 子句并始终返回 memo[n],无论是否存在缓存命中或未命中。

标签: python recursion dynamic-programming memoization coin-change


【解决方案1】:

谢谢@user2864740@dannyadam

我将把我的最终代码留给以后查看帖子的人。

def coinFlipping(n):
    """
    For n amount of cents, return the minimal amount of currency in coins.

    Top-Down Approach (Memoization): Memo dictionary stores already solved
    subproblems to reuse and avoid recomputing. It's essentially recursion 
    but optimized to avoid recomputing results. 
    """
    COINS = {
        "dollar": 100,
        "quarter": 25,
        "dime": 10,
        "nickel": 5,
        "penny": 1
    }

    memo = {}

    def __coinFlipping(change):

        if change not in memo:
            # Base case (if n is equal to 0.01, 0.05, 0.10, 0.25..)
            if change in COINS.values():
                memo[change] = 1
            else:
                results = []
                coins = [coin for coin in COINS.values() if coin < change]
                for coin in coins:
                    results.append(__coinFlipping(change - coin))
                memo[change] = 1 + min(results)
        return memo[change]         
            
    __coinFlipping(n)
    print(memo[n])

coinFlipping(42)


在实现了这个例子之后,我开始认为这是一个糟糕的记忆玩具例子。我本可以编写一个贪心算法来在每一步中选择最大价值的硬币。例如从 42c 中减去 25c 并从 17c 中减去 10c 等等,同时递增一个计数器。

【讨论】:

    【解决方案2】:

    user2864740 是正确的。更改为整数并运行代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-11
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      • 2019-07-17
      • 1970-01-01
      • 2012-10-27
      相关资源
      最近更新 更多