斐波那契:时间复杂度和大O表示法

时间:2019-06-21 03:28:11

标签: python python-3.x

我从不同的教程站点上看到了Fibonacci的几种解决方案,我注意到的一件事是,它们具有通过递归函数解决问题的相同方法。我测试了递归函数,它花了77秒才获得列表中的第40个项目,因此我尝试制作一个函数而不通过for循环处理递归函数,并且只用了不到一秒钟的时间。我说对了吗?我的功能的O符号是什么?

from time import time


def my_fibo(n):
    temp = [0, 1]
    for _ in range(n):
        temp.append(temp[-1] + temp[-2])
    return temp[n]


start = time()
print(my_fibo(40), f'Time: {time() - start}')
# 102334155 Time: 0.0

vs

from time import time
def recur_fibo(n):
    if n <= 1:
        return n
    else:
        return recur_fibo(n - 1) + recur_fibo(n - 2)


start = time()
print(recur_fibo(40), f'Time: {time() - start}')
# 102334155 Time: 77.78924512863159

2 个答案:

答案 0 :(得分:2)

您所做的是时空权衡的一个示例。

在第一个(迭代)示例中,您有一个O(n)时间算法,该算法也占用O(n)空间。在此示例中,您存储了值,因此您无需重新计算它们。

在第二个(递归)示例中,您有一个O(2 ^ n)时间的算法(有关更多详细信息,请参见Computational complexity of Fibonacci Sequence),该算法也占用了堆栈上的大量空间。

在实践中,后一个递归示例是处理Fibonacci序列的“幼稚”方法,存储先前值的版本明显更快。

答案 1 :(得分:0)

对于big-O,答案就在上面:在您展示的经典递归实现中,该函数在每次遍历中两次调用自身。

在下面的示例中,我编写了一个递归函数,该函数在每次通过中仅调用一次,因此它也具有O(n):

def recur_fibo3(n, curr=1, prev=0):
    if n > 2: # the sequence starts with 2 elements (prev and curr)
        newPrev = curr
        curr += prev
        return recur_fibo3(n-1, curr, newPrev) # recursive call
    else:
        return curr 

它与n的增加呈线性关系,但比正常循环慢。

此外,您还可以注意到,两个递归函数(经典函数和上一个函数)都没有存储整个序列供您返回。您的循环函数可以执行此操作,但是如果您只想检索序列中的第n个值,则可以编写一个更快的函数,如下所示:

def my_fibo2(n):
    prev1 = 0
    prev2 = 1
    for _ in range(n-2):
        curr = prev1 + prev2
        prev2 = prev1
        prev1 = curr
    return curr

使用%timeit来衡量执行时间,我们可以看到哪个更快。但是它们在正常情况下都足够快,因为您只需要计算一次长序列并将结果存储起来以备后用...:)

Time to return the 100th element in Fibonacci series

my_fibo(100)
10.4 µs ± 990 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

my_fibo2(100)
5.13 µs ± 1.68 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)

recur_fibo3(100)
14.3 µs ± 2.51 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)

============================================
Time to return the 1000th element in Fibonacci series

my_fibo(1000)
122 µs ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

my_fibo2(1000)
82.4 µs ± 17.3 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

recur_fibo3(1000)
207 µs ± 19.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)