@looper1211
2018-12-13T10:24:26.000000Z
字数 3027
阅读 790
数学上,斐波那契数列以递归的形式进行定义:
我们可以按照递归的方式计算F(n)的值,但是存在大量的重复计算,当N的数据过大时,会造成堆栈溢出问题,代码如下:
def fib(n):
if n == 0:
return 0
if n == 1 or n == 2:
return 1
return fib(n - 1) + fib(n - 2)
从规模上来说,如果需要计算F(4)的值,需要进行9次元素操作
设T(n)为计算n的时间复杂度,那么
粗略估算,,上述代码求解F(n)的计算,它的时间复杂度是,可以看出这是一个指数时间
我们发现上述递归中,存在重复计算的情况,所以可以采用迭代方式记录每次求解出来的值
def fib(n):
fibs = [0] * (n + 1)
fibs[1] = 1
for i in range(2, n + 1):
fibs[i] = fibs[n - 1] + fibs[n - 2]
return fibs[n]
上述代码中我们其实只需要F(n)的值,其他的值的内存空间其实也可以重复利用,优化后如下,
def fib(n):
f1 = 0
f2 = 1
while n:
f1, f2 = f2, f1 + f2
n -= 1
return f1
从定义开始:
这里可以利用快速幂运算求解,假设计算A的N次幂,二阶矩阵的乘法满足结合律
设A,B,C都是任意的二阶矩阵,则
我们设定:
当n为奇数:
相当于
这样可以减少计算次数,因为这里有5个乘, 计算完 得到结果,再乘以 这里用了3个乘
以下是普通数据的快速幂运算,运算改为矩阵乘法,ret改为单位矩阵即可
def qpow(base, exp):
if exp == 0:
return 1
ret = 1
while exp:
if exp & 1:
ret = ret * base
base = base * base
exp >>= 1
return ret
我们可以设定:
那么
这里需要注意一点 n 需要进行奇偶性判定:
当n为奇数时: 此时,
当n为偶数时:,此时
所以计算F(N)的值,只需要知道F(n/2+1)和F(n/2)即可
def fib(n):
if n < 1:
return (1, 0)
f_m_1, f_m = fib(n >> 1)
if n & 1:
return f_m_1 * (f_m_1 + 2 * f_m), f_m ** 2 + f_m_1 ** 2
else:
return f_m_1 ** 2 + f_m ** 2, f_m * (2 * f_m_1 - f_m)