如何改进这个代码 - 斐波那契的总和

时间:2015-10-20 11:23:23

标签: python python-2.7

此代码是否有更快的版本?

def perimeter(n):
    a = [1, 1]
    for i in range(n-1):
        a.append(a[i+1]+a[i])
    return 4*sum(a)

我试图在代码大战上解决一些任务,但是有一个错误:

  

流程已终止。完成时间超过6000毫秒

3 个答案:

答案 0 :(得分:0)

不使用斐波那契数的总和公式(在http://math.stackexchange.com上询问),你的解决方案应该和它一样快。使用矩阵形式不应该有很多帮助,因为你必须进行取幂。

但是,您可以先使用xrange而不是range来避免内存分配(您使用的是python2)。而且还没有将数字存储在不断增长的数组中:

def perimeter(n):
    a, b = 1, 1
    s = a+b

    for i in xrange(n-1):
        a, b = b, a+b
        s+=b

    return 4*s 

公式解决方案(使用斐波纳契数最多为F(j)的总和为F(j + 2)-2)将是:

def perimeter(n)
    if n == 0:
       return 8 # a special case where you add the two first fibonacci numbers anyway.
    n = n+3

    phi = (math.sqrt(5)-1)/2

    return 4*int(round((phi**n - (-phi)**(-n))/math.sqrt(5)))-4 

使用最后一个解决方案时要小心,因为你最终会得到舍入错误,这会让你错过Fibonacci数字。

为了解决准确性问题,我们可以使用a+b*sqrt(5)形式的正式表达式。为简单起见,我将它们封装在一个类中:

class Golden:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __mul__(self, other):
        return Golden( self.a*other.a + 5*self.b*other.b,
                       self.a*other.b + self.b*other.a )

    def __pow__(self, n):
        if n == 1:
            return self

        if n % 2 == 0:
            return (self * self) ** (n/2)
        return self * (self * self) ** ((n-1)/2)

    def __add__(self, other):
        return Golden(self.a + other.a, self.b+other.b)

    def __sub__(self, other):
        return Golden(self.a - other.a, self.b-other.b)

def perimeter3(n):
    if n == 0:
        return 8

    n = n+3

    phi = Golden(1,1)
    psi = Golden(1,-1)

    fn = (phi**n - psi**n)

    assert fn.a == 0

    return 4*(fn.b / (2 ** n)-1)

这有一个轻微的缺点,它迭代地计算功率,但是这样做所需的步骤数不是n,而是log(n),它应该使它比第一个解决方案更具优势(中间的缺点只有在准确性使中间解决方案失败之前才有意义 - 这只适用于小的n。)

答案 1 :(得分:0)

您可以生成斐波纳契对:

def fibonacci_pairs(n):
    a, b = 0, 1
    for i in xrange(n):
        yield a, b
        a, b = b, a + b

然后:

>>> sum(b for a, b in fibonacci_pairs(10))

答案 2 :(得分:0)

你可以注意到一个数学事实。我们a0, a1, a2 ...是斐波纳契数。您想要计算此声明:

a0 + a1 + a2 + a3 + ... + an = Sn

另一方面,a = a {n-1} + a {n-2}:

Sn = 2*a{n-1} + 2*a{n-2} + a{n-3} + ... + a1 + a0 = (2*a{n-1} + 2*a{n-2} + 2*a{n-3} + ... + 2*a1 + 2*a0) - (a{n-3} + ... + a1 + a0) = 2*S{n-1} - S{n-3}

换句话说,我们得到了一个递归语句:

Sn = 2*S{n-1} - S{n-3}

使用python我们可以编写这样的函数:

cache = {}
def S(n):
    if n in cache:
        return cache[n]
    if n <= 2:
        return n
    else:
        r = 2 * S(n - 1) - S(n - 3)
        cache[n] = r
        return r

def perimeter(n):
    return 4 * S(n)

print S(1000) # it prints 113796925398360272257523782552224175572745930353730513145086634176691092536145985470146129334641866902783673042322088625863396052888690096969577173696370562180400527049497109023054114771394568040040412172632375