在Python中优化递归Padovan(即具有垂死的兔子的Fibonacci)算法

时间:2017-05-20 04:45:22

标签: python algorithm recursion optimization fibonacci

对于Python(我刚刚在两周前开始学习它),我是一个新手,但我在完成挑战时有很多乐趣。给我带来麻烦的一个挑战是使用致死兔子的斐波那契序列的变异(即Padovan序列,但具有可变的寿命)。

经过多次试验和错误,我编写了一个代码,返回的输出与我为不同的生命周期设置所做的表格相匹配。然而,算法在大约40转时变得非常慢,并且寿命超过15个月,并且挑战是定时的。我的代码是:

def fib(n):
    if n == 1:
        return 1
    elif n == 2:
        return 1
    else:
        return fib(n-1) + fib(n-2)



def fibd(n, m):
    if n < (m+2) and m > 3:
        return fib(n)
    elif n < (m+1) and m == 3:
        return fib(n)
    elif n >= (m+1) and m==3:
        return fibd(n-2, m) + fibd(n-3, m)
    elif n >= (m+2) and m > 3:
        return sum(map(fibd, [n-(m+x) for x in (range(-(m-2), 2))], [m]*m))

这就像我能用我的谦虚技能一样简单,但我不知所措。 n表示我们停止计数的转弯次数,m表示每只兔子在死亡前的转弯次数。基本上,第一个函数给出Fibonacci序列。这是因为在兔子实际死亡之前,Padovan泛化与Fibonacci序列相同,所以我需要回调它作为递归的一部分。然后,有一个单独的代码块,寿命为3,因为对于4或更多的寿命,在第n个转弯处获得兔子数的公式是(n-2)+(n-3).. 。(n-(m + 1)),寿命为3,公式不同(它只是(n-2)+(n-3)。下一个代码块的寿命为4或更大。< / p>

如果您没有完整的解决方案,任何输入都会受到赞赏,甚至是一些提示。我有兴趣学习如何优化,就像我有兴趣解决这个特殊问题一样,因为这不是为了工作或学校,而是为了我自己的启发。

2 个答案:

答案 0 :(得分:0)

你的两个函数都具有指数时间复杂度,所以它们会很慢。您需要找到更好的算法。在你想的时候,你可能想用Python运行这个程序,比如fibs(50),看看它做了什么:

def fibs(n):
    a,b = 1,1
    while n > 0:
        print a
        a,b,n = b,a+b,n-1

答案 1 :(得分:0)

下面是一个代码的返工,它具有更好的递归Fibonacci函数(虽然没有迭代那么快)和 memoizing ,@ johnY无法在评论中找到它,来自博客{{ 3}}

单独升级的斐波那契功能可将速度提高约20倍。 memoize装饰器缓存值,因此它们不会重新计算,将速度提高40倍。 (我对fibd()的重写在性能方面没有任何区别,叹息。)

def memoize(f):
    cache = {}
    return lambda *args: cache[args] if args in cache else cache.update({args: f(*args)}) or cache[args]

@memoize
def fib(n, res=0, nxt=1):
    if n == 0:
        return res
    return fib(n - 1, nxt, res + nxt)

@memoize
def fibd(n, m):
    if m > 3:
        if n < (m + 2):
            return fib(n)

        return sum(map(fibd, (n - (m + x) for x in range(2 - m, 2)), [m] * m))

    elif m == 3:
        if n < (m + 1):
            return fib(n)

        return fibd(n - 2, m) + fibd(n - 3, m)

print(fibd(40, 15))

我的系统的总体性能从47秒变为1/20秒。但是,我只测试了fibd(40, 15)案例,您需要对此修改后的代码进行更多测试。