You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修复硬币找零算法中的记忆化实现问题

修复你的递归+记忆化硬币找零方案

老哥,我明白你想通过优化自己的递归解法来理解原理,而不是直接换其他思路——这种抠细节的学习方式真的很棒!

问题核心:记忆化的键缺了关键状态

你现在的记忆化字典只把目标金额n当键,但实际上,不同的可用硬币范围下,同一个n的找零方式数是完全不同的。举个例子:

  • 当n=10,只能用5的时候,只有1种找零方式(5+5);
  • 当n=10,可以用5和10的时候,有2种找零方式(5+5、10)。

你的代码里第一次计算n=10时是在「只能用5」的场景,把d[10]设为1,后面再遇到「可以用5和10」的n=10时,直接返回了这个错误的结果,自然就漏掉了(10,5,5)这种组合。

解决方案:把「可用硬币范围」加入记忆化键

我们需要把记忆化的键从单纯的n,改成(n, 当前可用的硬币特征)——这里的特征可以是允许使用的硬币元组,或者更高效的、排序后硬币的最大索引。

方案1:贴合你原逻辑的修改

直接把当前允许使用的硬币列表转成元组(因为列表不能当字典键),作为记忆化键的一部分:

d = {}
def make_change(n, coins):
    # 先排序硬币,避免因原顺序不同导致的重复场景
    sorted_coins = sorted(coins)
    # 用(n, 硬币元组)作为记忆化键
    key = (n, tuple(sorted_coins))
    
    if key in d:
        return d[key]
    
    # base case
    if n < 0:
        return 0
    if n == 0:
        return 1
    
    total = 0
    for coin in sorted_coins:
        # 只允许使用<=当前硬币的币种,和你原逻辑一致
        allowed_coins = [c for c in sorted_coins if c <= coin]
        total += make_change(n - coin, allowed_coins)
    
    d[key] = total
    return total

# 测试:应该返回3
print(make_change(20, [5,10]))

方案2:更高效的索引优化

我们可以先把硬币排序,然后用「最大硬币的索引」来代替整个硬币列表,这样键的体积更小,查找和存储效率更高:

d = {}
def make_change(n, coins, max_idx):
    # 用(n, 最大硬币索引)作为记忆化键
    key = (n, max_idx)
    
    if key in d:
        return d[key]
    
    # base case
    if n < 0:
        return 0
    if n == 0:
        return 1
    
    total = 0
    # 遍历从0到max_idx的所有硬币
    for i in range(max_idx + 1):
        current_coin = coins[i]
        # 递归时限制只能用当前硬币及更小的(即索引<=i)
        total += make_change(n - current_coin, coins, i)
    
    d[key] = total
    return total

# 调用前先排序硬币,传入最后一个硬币的索引
sorted_coins = sorted([5,10])
print(make_change(20, sorted_coins, len(sorted_coins)-1))  # 返回3

为什么这样能解决问题?

现在记忆化的键包含了当前递归的完整状态:不仅有目标金额n,还有当前允许使用的硬币范围。这样不同场景下的结果会被分别存储,不会互相覆盖,自然就能统计到所有唯一的找零方式了。

内容的提问来源于stack exchange,提问作者Optimesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:56:31