算法之矩阵计算斐波那契数列
算法之矩阵计算斐波那契数列
本节内容
- 斐波那契介绍
- 普通方式求解斐波那契
- 矩阵概念
- 矩阵求幂
- 矩阵求解斐波那契
1.斐波那契介绍
斐波那契数列有关十分明显的特点,那是:前面相邻两项之和,构成了后一项。即f(n)=f(n-1)+f(n-2),f(0)=0,f(1)=f(2)=1,推导下去f(3)=2,f(4)=3,f(5)=5。。。。。。
2.普通方式求解斐波那契
按照上面提供的推导公式,普通方式求解斐波那契数列代码如下:
1 def normal(n): 2 a,b,c=0,1,1 3 while n: 4 a,b,c=b,c,b+c 5 n-=1 6 return a
使用上面的方式求解第n项斐波那契数列的时间复杂度为O(n),也就是说,时间复杂度随着n的增长而线性增长。
3.矩阵概念
开始,先来介绍一下矩阵的概念:在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,最早来自于方程组的系数及常数所构成的方阵。
这里不介绍矩阵的各方面知识了,如果那样的话。。。就是一篇数学笔记了。。。这里只讲解矩阵相乘的概念。
矩阵相乘:矩阵相乘最重要的方法是一般矩阵乘积。它只有在第一个矩阵的列数(column)和第二个矩阵的行数(row)相同时才有意义。一般单指矩阵乘积时,指的便是一般矩阵乘积。一个m×n的矩阵就是m×n个数排成m行n列的一个数阵。由于它把许多数据紧凑的集中到了一起,所以有时候可以简便地表示一些复杂的模型。
设A为m*p的矩阵,B为p*n的矩阵,那么称m*n的矩阵C为矩阵A与B的乘积,记作C=AB:
4.矩阵求幂
上面已经介绍过了矩阵相乘的概念了,那么,斐波那契该怎么由矩阵标示呢?
从第三项开始,每一项都是前两项之和。 F(n)=F(n−1)+F(n−2), n⩾3 把斐波那契数列中 相邻的两项F(n)和F(n−1)写成一个2×1的矩阵。
斐波那契数列用矩阵推导如下:
求F(n)等于求二阶矩阵的n - 1次方,结果取矩阵第一行第一列的元素。
问题转换为二阶矩阵的n次幂。
而计算二阶矩阵的N次幂运算,由于二阶矩阵乘法满足结合律,这样,可以快速计算二阶矩阵的n次幂运算。
假设A为一个二阶矩阵,则A的幂运算满足下面的条件:
A**6=A**3∗A**3
A**7=A**3∗A**3∗A**1=A**4*A**2*A**1
在这里,我们可以类似地把A看做是二进制中的2,2**7=2**4*2**2*2**1也就是说可以把矩阵的幂转换成二进制来表示。从而可以将n次幂拆解成长度为logn的二进制数来表示:7=111(二进制)。
这就是快速求二阶矩阵的核心方法。
5. 矩阵求解斐波那契
前戏做足了,下面就该秀代码了。
1 def multi(a,b): # 计算二阶矩阵的相乘 2 c=[[0,0],[0,0]] # 定义一个空的二阶矩阵 3 for i in range(2): 4 for j in range(2): 5 for k in range(2): # 新二阶矩阵的值计算 6 c[i][j]=c[i][j]+a[i][k]*b[k][j] 7 return c 8 9 10 def matrix(n): 11 base=[[1,1],[1,0]] # 元矩阵,这里可以把元矩阵看做是2**0=1 12 ans=[[1,0],[0,1]] # 结果矩阵 最开始的结果矩阵也可以看做是1,因为这个矩阵和任意二阶A矩阵相乘结果都是A 13 while n: 14 if n&1: # 取n的二进制的最后一位和1做与运算,如果最后一位是1,则进入if体内部 15 ans=multi(ans,base) # 如果在该位置n的二进制为1,则计算ans和base矩阵 16 base=multi(base,base) # base矩阵相乘,相当于初始base矩阵的幂*2 17 n>>=1 # n的二进制往右移一位 18 return ans[0][1] # 最后获取到的二阶矩阵的[0][1]即f(n)的值
最后把例子的完整代码贴出来:
1 import time 2 3 4 def multi(a,b): 5 c=[[0,0],[0,0]] 6 for i in range(2): 7 for j in range(2): 8 for k in range(2): 9 c[i][j]=c[i][j]+a[i][k]*b[k][j] 10 return c 11 12 13 def matrix(n): 14 base=[[1,1],[1,0]] 15 ans=[[1,0],[0,1]] 16 while n: 17 if n&1: 18 ans=multi(ans,base) 19 base=multi(base,base) 20 n>>=1 21 # for i in range(2): 22 # print(ans[i]) 23 return ans[0][1] 24 25 def normal(n): 26 a,b,c=0,1,1 27 while n: 28 a,b,c=b,c,b+c 29 n-=1 30 return a 31 32 n=int(input(">>>")) 33 start=time.time() 34 print("Normal:",normal(n)) 35 print("use:",time.time()-start) 36 start=time.time() 37 print("Matrix:",matrix(n)) 38 print("use:",time.time()-start) 39 #计算结果 40 >>>65536 41 Normal: 731992144602...... 42 use: 0.07219505310058594 43 Matrix: 731992144602...... 44 use: 0.023076772689819336
可以看出来当n的值越来越大的时候,两种方式计算出结果的时间差距将越来越大,正常的计算时间复杂度是O(n),矩阵求值的时间复杂度是O(logn)。
后记:
由此可以看出,使用推导式f(n)=f(n-1)+f(n-2)求斐波那契的第n项的算法复杂度极限为O(n),这是一维世界下的极限。将其从一维上升到二维,用二阶矩阵推导斐波那契数列时,计算的算法复杂度为O(logn),也就是说,使用升维的手段将一维空间进行扭曲从而将距离缩短,可以更快的计算出结果。
由此推导出如果人来要突破光速的极限,需要将现有的三维空间升级到四维空间,扭曲空间从而缩短距离,达到突破光速的目的。
- 第六篇:算法之矩阵计算斐波那契数列
- Strassen矩阵乘法 + 快速计算乘方的算法 + 矩阵的次幂
- 设M 是一个m×n 的矩阵,其中每行的元素从左到右单增有序,每列的元素从上到下单增有序。 给出一个分治算法计算出给定元素x 在M 中的位置或者表明x 不在M 中。分析算法的时间复杂性。
- 利用投影算法来计算系统矩阵左乘和右乘
- Strassen矩阵乘法 + 快速计算乘方的算法 + 矩阵的次幂
- 计算矩阵边缘元素之和 (Coursera 程序设计与算法 专项课程2 C程序设计进阶 李戈;OpenJudge)
- 利用MPICH2计算矩阵相乘的简单算法
- 使用SIFT和RANSAC算法,完成特征点的正确匹配,并求出变换矩阵,通过变换矩阵计算出要识别物体的边界
- 基于矩阵分解的推荐算法-梯度下降算法-非并行计算[转载]
- 斐波那契数列(二)--矩阵优化算法
- 设M 是一个m×n 的矩阵,其中每行的元素从左到右单增有序,每列的元素从上到下单增有序。 给出一个分治算法计算出给定元素x 在M 中的位置或者表明x 不在M 中。分析算法的时间复杂性。
- GPU上大规模稀疏矩阵特征值计算高效算法之三——SLEPc测试
- 矩阵在计算斐波那契数列的运用
- 大矩阵 svd 近似计算算法
- 利用投影算法来计算系统矩阵左乘和右乘
- 计算斐波那契数列,两种方法,打开注释掉的语句你会感受到算法的力量
- 算法学习之一(二):矩阵计算——LU分解
- 关于Floyd-Warshall算法由前趋矩阵计算出的最短路径反映出了算法的执行过程特性的证明
- 转置矩阵的分块并行乘法(C语言实现),计算矩阵C[rawn][rawn]=A[rawm][rawn]'*B[rawm][rawn],子块大小为S*T,其算法实现原理参加本代码的附件。
- 利用投影算法来计算系统矩阵左乘和右乘