python中的memoization fibonacci算法

时间:2015-04-10 21:20:50

标签: python algorithm memoization

我有这种记忆技术来减少获得Fibonacci序列号的调用次数:

def fastFib(n, memo):
    global numCalls
    numCalls += 1
    print 'fib1 called with', n
    if not n in memo:
        memo[n] = fastFib(n-1, memo) + fastFib(n-2, memo)
        return memo[n]


def fib1(n):
    memo = {0:1, 1:1}
    return fastFib(n, memo)


numCalls = 0
n = 6
res = fib1(n)
print 'fib of', n,'=', res, 'numCalls = ', numCalls

但我被困在这里:memo[n] = fastFib(n-1, memo) + fastFib(n-2, memo)memo = {0:1, 1:1}。每次我想得到一个数字的时候,它是如何完全减少通话次数的呢?

4 个答案:

答案 0 :(得分:4)

您应该始终返回memo[n],不仅仅是在不可靠的查找(fastFib()的最后一行):

def fastFib(n, memo):
    global numCalls
    numCalls += 1
    print 'fib1 called with', n
    if not n in memo:
        memo[n] = fastFib(n-1, memo) + fastFib(n-2, memo)
    #this should be outside of the if clause:
    return memo[n] #<<<<<< THIS

通过这种方式减少了调用次数,因为对于n的每个值,您实际上最多只能计算和递归一次,将递归调用的数量限制为O(n)2n的上限。 1}} invokations),而不是一遍又一遍地重新计算相同的值,有效地进行指数的递归调用。

fib(5)的一个小例子,其中每一行都是递归调用:

天真的方法:

f(5) = 
f(4) + f(3) = 
f(3) + f(2) + f(3) =
f(2) + f(1) + f(2) + f(3) =
f(1) + f(0) + f(1) + f(2) + f(3) = (base clauses) = 
1 + f(0) + f(1) + f(2) + f(3) = 
2 + f(1) + f(2) + f(3) =
3 + f(2) + f(3) = 
3 + f(1) + f(0) + f(3) = 
3 + 1 + f(0) + f(3) = 
5 + f(3) = 
5 + f(2) + f(1)  =
5 + f(1) + f(0) + f(1) =
5 + 1 + f(0) + f(1) =
5 + 2 + f(1) =
8

现在,如果你使用memoization,你不需要重新计算很多东西(比如计算3次的f(2)),你得到:

f(5) = 
f(4) + f(3) = 
f(3) + f(2) + f(3) =
f(2) + f(1) + f(2) + f(3) =
f(1) + f(0) + f(1) + f(2) + f(3) = (base clauses) = 
1 + f(0) + f(1) + f(2) + f(3) = 
2 + f(1) + f(2) + f(3) =
3 + f(2) + f(3) =  {f(2) is already known}
3 + 2 + f(3) = {f(3) is already known}
5 + 3  = 
8

如您所见,第二个比第一个短,数字越大(n),这个差异越大。

答案 1 :(得分:3)

可以使用Python 3.2 +

中的 functools 库完成
import functools

@functools.lru_cache(maxsize=None) #128 by default
def fib(num):
    if num < 2:
        return num
    else:
        return fib(num-1) + fib(num-2)

答案 2 :(得分:0)

以下方法使用最小的缓存大小(2个条目),同时提供O(n)渐近性:

from itertools import islice
def fibs():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

def fib(n):
    return next(islice(fibs(), n-1, None))

此实现来自斐波纳契的经典核心递归定义(la Haskell的https://wiki.haskell.org/The_Fibonacci_sequence#Canonical_zipWith_implementation)。

有关更直接(递归)的翻译,请参见https://gist.github.com/3noch/7969f416d403ba3a54a788b113c204ce

答案 3 :(得分:0)

它可以在单个类或函数中完成,如下所示

class Solution:
    def __init__(self):
        # initialize memo
        self.memo = {}


    def fib(self, n: int) -> int:
        # base case
        if n < 2:
            return n

        # check if fib(n) is already in memo - f(n) was calculated before
        if n in self.memo:
            return self.memo[n]
        else:
            f = self.fib(n - 1) + self.fib(n - 2)

        # store the value of fib(n) when calculated 
        self.memo[n] = f 
   
        return f