记忆:用硬币找零

Posted

技术标签:

【中文标题】记忆:用硬币找零【英文标题】:Memoization: Making change with coins 【发布时间】:2015-07-03 22:00:42 【问题描述】:

我正在用 Python 解决经典的用硬币找零问题。这是我的实现。

def memo(fn):
    def helper(*args): # here, * indicate the fn take arbitrary number of argumetns
        d = 
        if args in d:
            return d[args] # args is a tuple, immutable, hashable
        else:
            res = fn(*args) # here * expand a tuple as arguments
            d[args] = res
            return res
    return helper

@memo
def change(options, n):
    if n < 0 or options ==():
        return 0
    elif n == 0:
        return 1
    else:
        return change(options, n- options[0]) + change(options[1:], n)

事实证明,memoized 版本比原始版本还要慢!为什么?我的实现出了什么问题?

这是没有记忆的:

In [172]: %timeit change((50, 25, 10, 5, 1), 100)
100 loops, best of 3: 7.12 ms per loop

这是有记忆的:

In [170]: %timeit change((50, 25, 10, 5, 1), 100)
10 loops, best of 3: 21.2 ms per loop

【问题讨论】:

您正在创建一个新的 "cache" 字典每次调用装饰函数时 这种技术的术语是“记忆”,而不是“记忆”。不要相信你的拼写检查器。 感谢指正。我一直认为是背诵orz。现在我知道人脑有多么强大可以自动填充幻想 XD 【参考方案1】:

在您当前的代码中:

def memo(fn):
    def helper(*args):
        d = 

您创建一个新的“缓存”字典d每次调用装饰函数时。难怪它变慢了!最小的修复是:

def memo(fn):
    d = 
    def helper(*args):

但它通常会更整洁。我用:

def memo(func):
    def wrapper(*args):
        if args not in wrapper.cache:
            wrapper.cache[args] = func(*args)
        return wrapper.cache[args]
    wrapper.cache = 
    return wrapper

这使得访问修饰函数的cache 进行错误修复等变得更加容易。

【讨论】:

哇,所以您将字典作为字段分配给包装函数对象。这有点干净。谢谢!!

以上是关于记忆:用硬币找零的主要内容,如果未能解决你的问题,请参考以下文章

记忆硬币变化

硬币找零(动态编程)

硬币找零问题的动态规划实现

最小硬币找零问题 - 回溯

最少硬币找零问题-动态规划

为啥贪心硬币找零算法对某些硬币组不起作用?