一.题目:
已知F[n]=F[n-1]+F[n-2],F[1]=1,F[2]=1,求给定n的F[n]
二. 思路
常见的方法就是动态规划,这样时间的复杂度为O(n)
还有一种更快速的方法:矩阵的快速幂
给出的递推式可以看做状态转移矩阵,可以表示为:
那么F[n]和F[0],F[1]的关系可以表示为
如何暴力求解转移矩阵的n-1方,求矩阵的次数为n-2次,每次两两矩阵相乘的复杂度为2*2*2,也就是时间复杂度为O(8*n)
反而比动态规划高了
这里就用到求矩阵快速幂的方法,将时间的复杂度降到O(8logn)
矩阵快速幂就是:比如我求解上面矩阵
的7次方幂T^7,因为用于动态规划的转移矩阵T都是方阵(好好想一下为什么),T^2之后还是维度不变的方阵,比如T的维度是2*2,那么T^2的维度还是2*2,也就是说维度不会随着幂的增加而增加,所以对于7次方,我们分解成:(((T^2)*T)^2)*T
也就是将幂7分解成(2+1)*2+1
这样的话求解矩阵乘的次数变成了4,这样的话总的求解矩阵乘法次数N满足logn<N<2logn(想一想为什么),时间复杂度还是O(logn)级别
三.Python实现如下
import time
def mat_mul(T1,T2):
n=len(T1)#结果的行数
m=len(T2[0])#结果的列数
res=[[0 for i in range(m)] for j in range(n)]
for i in range(n):
for j in range(m):
res[i][j]=sum([T1[i][k]*T2[k][j] for k in range(len(T1[0]))])
return res
def Fbi(n):
start = time.clock()
c=[[1,1],[1,0]]
res=[[1,1],[1,1]]
if 0<n<3:
return 1
n=n-2
while n:
if n%2:
res=mat_mul(res,c)
c=mat_mul(c,c)
n=n>>1
res=mat_mul(res,[[1],[1]])
elapsed = (time.clock() - start)
print("Time used:",elapsed)
return res[0][0]
参考链接:
讲的非常详细,基础: