记忆:用硬币改变

Luc*_*hen 2 python memoization dynamic-programming coin-change python-decorators

我正在研究用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)
Run Code Online (Sandbox Code Playgroud)

事实证明,memoized版本甚至比原始版本更慢!为什么?我的实施出了什么问题?

这没有记忆:

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

这是memoization:

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

jon*_*rpe 7

在您当前的代码中:

def memo(fn):
    def helper(*args):
        d = {}
Run Code Online (Sandbox Code Playgroud)

每次调用修饰函数时都会创建一个新的"缓存"字典.难怪它慢一点!最小的修复是:d

def memo(fn):
    d = {}
    def helper(*args):
Run Code Online (Sandbox Code Playgroud)

但它一般可以整洁.我用:

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
Run Code Online (Sandbox Code Playgroud)

这使得访问修饰函数更容易cache进行错误修复等.