斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*)
第一种:递推方法
递推法,就是递增法,时间复杂度是 O(n),呈线性增长,如果数据量巨大,速度会越拖越慢
- for循环
def fib(n): if n < 0: raise IndexError('Index out of range') a, b = 0, 1 for _ in range(n): # 这里for遍历的时候元素不重要也不需要,所以写的_ a, b = b, a + b return a
测试是否实现基本功能
for i in range(9): print(fib(i),end='\t') C:\Users\zhuzhupoo\AppData\Local\Programs\Python\Python39\python.exe "D:/PyCharm 2021.3.3/py/feibolaqie.py" 0 1 1 2 3 5 8 13 21 Process finished with exit code 0
print(fib(-1)) C:\Users\zhuzhupoo\AppData\Local\Programs\Python\Python39\python.exe "D:/PyCharm 2021.3.3/py/feibolaqie.py" Traceback (most recent call last): File "D:\PyCharm 2021.3.3\py\feibolaqie.py", line 29, in <module> print(fib(-1)) File "D:\PyCharm 2021.3.3\py\feibolaqie.py", line 12, in fib raise IndexError('Index out of range') IndexError: Index out of range Process finished with exit code 1
- while循环
def fib(n): if n < 0: raise IndexError('Index out of range') a, b = 0, 1 while n > 0: a, b = b, a + b n -= 1 return a
功能测试与for的测试一致
第二种:递归方式
def fib(n): if n < 0: raise IndexError('Index out of range') elif n == 0: return 0 elif 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)
由于有大量重复计算,我们可以稍微优化一下,设置一下缓存
from functools import lru_cache @lru_cache def fib(n): return 1 if n < 3 else fib(n-1) + fib(n-2)
第三种:用一个类写出比较全面的斐波拉契
class Fib: """一个方便调用的斐波拉契数列""" def __init__(self): self.items = [0, 1, 1] # 定义斐波拉契数列前3项(0,1,2) def __str__(self): # 提供可视化输出 return str(self.items) # def __repr__(self): # return self.__str__() __repr__ = __str__ # 提供不同情况下的可视化输出,简化上面的代码 def __len__(self): # 提供长度方法 return len(self.items) # 取列表的长度 def __iter__(self): # return iter(self.items) # 转化为一个生成器,与下面一行代码同功能 yield from self.items def __getitem__(self, index): # 提供索引方法 if index < 0: raise IndexError('Index out of range') # 索引为负数抛出异常 for i in range(len(self), index+1): # 计算列表中不包含的项 self.items.append(self.items[i-1] + self.items[i-2]) return self.items[index] # def __call__(self, index): # return self.__getitem__(index) # 提供实例调用方法,与下面一行代码功能一致,实际上都是将call丢给getitem处理 # return self[index] __call__ = __getitem__ # 简化上面的代码
测试是否实现基本功能
f = Fib() # 实例化 print(f) # 观察可视化是否实现 print(f[0], f[1], f[3],end='\t') # 观察能否使用实例索引 print(f(0), f(1), f(5),end='\t') # 观察实例能否调用 for i in range(9): print(f(i),end='\t') for x in f: # 打印列表中现有的项 print(x,end='\t') print(f) C:\Users\zhuzhupoo\AppData\Local\Programs\Python\Python39\python.exe "D:/PyCharm 2021.3.3/py/fib0130.py" [0, 1, 1] 0 1 2 0 1 5 0 1 1 2 3 5 8 13 21 0 1 1 2 3 5 8 13 21 [0, 1, 1, 2, 3, 5, 8, 13, 21] Process finished with exit code 0
print(f[-1]) C:\Users\zhuzhupoo\AppData\Local\Programs\Python\Python39\python.exe "D:/PyCharm 2021.3.3/py/fib0130.py" Traceback (most recent call last): File "D:\PyCharm 2021.3.3\py\fib0130.py", line 36, in <module> print(f[-1]) File "D:\PyCharm 2021.3.3\py\fib0130.py", line 21, in __getitem__ raise IndexError('Index out of range') # 索引为负数抛出异常 IndexError: Index out of range Process finished with exit code 1