首页 > 编程知识 正文

python求斐波那契数列前n项,python编写斐波那契数列

时间:2023-05-03 14:52:15 阅读:140305 作者:2703

0 .问题说明

在数学中,由斐波那契数字(Fibonacci number )表示

)组成的数组,称为斐波那契数列(Fibonacci sequence )。 这个数字序列中的每个数字都等于前面排列的两个数字之和。 数列从0和1开始:

数列中第n个(n1 )的数字如下

根据上述公式,通过计算得到的斐波那契数列如下。

随着n的增大,斐波那契数列的增长比例逐渐接近黄金分割比例。

本论文尝试使用递归法:时间复杂度这3种时间复杂度不同的算法来求解该序列的第n个数字

循环法:时间的复杂性

矩阵乘法:时间复杂性

(? 有讨论的余地)

1 .递归解法

根据斐波那契数列的计算公式:

中选择所需的族。 自然认为这个问题适合用递归法求解。 以下是直接的python代码。

effib_recur(n ) :

if n=1: # base case递归终止条件

return n

returnfib_recur(n-1 ) fib _ recur (n-2 ) #向下递归

时间复杂度分析

细心的读者应该可以观察到递归求解的过程就像建立二叉树一样。 例如,解开

依赖关系

我们现在

作为树的根节点,

继续向下递归、左节点作为左右2个叶节点

继续分解为

,右节点

继续分解为

中选择所需的族。 如下图所示。

因此,该算法的时间复杂度。

性能优化

指数复杂度太高了

响应时间长的话不能接受,好在有优化的空间。 从上面的二叉树可以看出,存在大量重复的节点。 优化的方法是将计算结果存入词典,每次计算时调查词典中是否已经存在同一节点,如果存在,则直接返回,否则将新节点存入词典。 优化后的步骤如下。

dic={} #词典

deffib_recur_with_DIC(n ) :

global dic #使用外部变量,必须先声明

if n=1: # base case递归终止条件

return n

查阅if n in dic: #词典

返回DIC [ n ]

未找到else: #

result=fib_recur_with_DIC(n-1 ) fib_recur_with_DIC (n-2 ) fib _ recur _ with _ DIC ) ) ) )。

DIC [ n ]=结果#存储结果

返回结果

优化后的程序相当于对前面的递归树进行剪枝的操作,因为同一个节点只执行了一次,所以减少了时间的复杂性。

2 .循环解法

假设前面的递归解法是自上而下地将大问题分解为小问题来求解,则循环解的规律是逆向思维,自下而上,首先求出小问题的解,然后进一步求出最终问题的解。

求解过程如下

单击,将每个步骤的结果保存到列表中与下标对应的位置。 代码如下所示。

effib_loop(n ) :

IFN=1: # 0,1直接返回

return n

fibs=[0] * (n 1 ) #初始化数组

fibs[1]=1

forIinrange(2,n 1 ) : #从下标为2的数字开始

fibs[i]=fibs[i-1] fibs[i-2]

return fibs[n] #返回第n个数字

时间复杂度分析

单层循环,时间的复杂性

中选择所需的族。 与优化的递归解法具有相同的复杂性。

性能优化

时间复杂度没有优化的空间,但可以使用两个

临时变量替换掉长度为

的列表,使空间复杂度从

降为

。代码如下:

def fib_loop_nolist(n):

if n <= 1: # 0,1 直接返回

return n

a, b = 0, 1

for i in range(2, n+1): # 从2开始

a, b = b, a + b

return b

3. 矩阵连乘法

根据斐波那契数列自身的性质,我们可以构造如下方等式关系:

使用矩阵表示上述等式关系,即

那么

依次乘下去,可得一般形式

我们要求解的

即为向量

的第一个分量。代码如下:

import numpy as np

def fib_matrix(n):

if n <= 1: # 0,1 直接返回

return n

result = np.mat([[1,1],[1,0]],dtype='float64')**(n-1) * np.mat([1,0]).T

return int(result[0,0])

时间复杂度分析

从程序上看,结果result几乎是一条语句返回的,这样看时间复杂度为

。但语句涉及到乘方运算,即n个矩阵相乘,时间复杂度似乎又是

。这一结论有待商榷。

性能优化

将矩阵对角化后,再进行连乘操作,可大大提升运算效率。对角化方法为

,其中

是要被对角化的矩阵,

为由

的特征向量组成的矩阵,

为由

的特征值构成的对角矩阵。

,python代码如下:

import numpy as np

def fib_matrix_diag(n):

if n <= 1: # 0,1 直接返回

return n

A = np.array([[1,1],[1,0]])

E = np.linalg.eig(A) # E中保存了A的特征值和特征向量

D = np.diag(E[0]) # 特征值对角矩阵

S = E[1] # 特征向量矩阵

result = np.mat(S) * np.mat(D)**(n-1) * np.mat(np.linalg.inv(S)) * np.mat([1,0]).T

return int(result[0,0])

问题

NumPy在处理矩阵乘法时会进行大量的浮点运算,在

时,结果的精度有损失。

4 小结经实际运行测试,不使用字典的递归算法在

时几乎慢到不可用的程度。

使用字典优化后的递归算法与循环算法性能相当,使用

测试运行时长大概在万分之一秒。

矩阵连乘算法虽看似简单,但运行效率不如循环算法,运行时长大概在千分之一秒,且矩阵对解化操作并没有带来明显的性能提升。

最终的运行效率排序为:循环法

递归(带字典)

矩阵连乘

递归(不带字典)。

参考

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。