斐波那契数列的四种求法与时间复杂度测算
定义:什么是斐波那契数列?
了解了斐波那契数列的特性,又该如何求解呢?不同方法所消耗的时间又是多少呢?接下来就做详细解析!
方法一: 普通循环法计算
%%timeit # 用于测算时间,将下面的函数重复执行多次,求出其平均值
a ,b= 0,1
for i in range(20):# 求斐波那契数列的前20项,如果求100以内的斐波那契数列只需修改判断语句即可
a,b=b,a+b
print(b) #
>>>2.57 µs ± 226 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
方法二: 使用递归的方法
%%timeit
def fib(n):
if n<3:
return 1
return fib(n-1)+fib(n-2)
#或者
def fib(n):
return 1 if n <3 else fib(n-1)+fib(n-2) #三元表达式写法
fib(20)
>>>3.4 ms ± 189 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
方法三: 递归与循环相结合
def fib(n,a=0,b=1):
a,b=b,a+b
if n ==1 :
return a
return fib(n-1,a,b)
>>>6.98 µs ± 96 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
方法四: 使用functools
中的lru_cache()
# 缓存记忆
import functools #导入functools 模块
@functools.lru_cache(maxsize = 100) #设定参数
%%timeit
def fib(n):
return 1 if n <3 else fib(n-1)+fib(n-2)
fib(20)
>>>3.16 ms ± 29.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
总结:
从上面的运行结果可以看出,不同的方法计算同一个范围内的斐波那契数列的时间是不相同的,而且差距很大(这里仅用前20个做了测试,读者可以加大测算范围).用循环的方法计算速度是最快的,递归的方法最慢.
其中:方法四与方法二的核心代码是一样的,不同的是方法四调用了functools
,该方法可以记住最近使用的内存,这样在计算时,如果使用到相同的函数,则立即返回该值,如求fib(30)时需要用到fib(29)与fib(28) .由于内存中已经存在了后者的数据,故只需读取即可,不需要在计算,因此可以大大节省运行时间.
测试如下:
#方法二
%%timeit
def fib(n):
return 1 if n <3 else fib(n-1)+fib(n-2)
fib(40)
1min 9s ± 8.08 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
#方法四
%%timeit
def finc():
import functools #导入functools 模块
@functools.lru_cache()
def fib(n):
return 1 if n <3 else fib(n-1)+fib(n-2)
fib(40)
finc()
42.9 µs ± 1.02 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
# 当数据量一大,二者的计算时间就会有明显的差异,因此,在使用递归时,需要考虑程序的运行时间.