[关闭]
@looper1211 2018-12-13T10:24:26.000000Z 字数 3027 阅读 790

从Fibonacci数列开始

数学上,斐波那契数列以递归的形式进行定义:

1. 递归计算

我们可以按照递归的方式计算F(n)的值,但是存在大量的重复计算,当N的数据过大时,会造成堆栈溢出问题,代码如下:

  1. def fib(n):
  2. if n == 0:
  3. return 0
  4. if n == 1 or n == 2:
  5. return 1
  6. return fib(n - 1) + fib(n - 2)

从规模上来说,如果需要计算F(4)的值,需要进行9次元素操作

设T(n)为计算n的时间复杂度,那么


一般情况,可以得出:

粗略估算,,上述代码求解F(n)的计算,它的时间复杂度是,可以看出这是一个指数时间

2. 迭代方式

我们发现上述递归中,存在重复计算的情况,所以可以采用迭代方式记录每次求解出来的值

  1. def fib(n):
  2. fibs = [0] * (n + 1)
  3. fibs[1] = 1
  4. for i in range(2, n + 1):
  5. fibs[i] = fibs[n - 1] + fibs[n - 2]
  6. return fibs[n]

上述代码中我们其实只需要F(n)的值,其他的值的内存空间其实也可以重复利用,优化后如下,

  1. def fib(n):
  2. f1 = 0
  3. f2 = 1
  4. while n:
  5. f1, f2 = f2, f1 + f2
  6. n -= 1
  7. return f1

3. 矩阵解决问题

从定义开始:


转化为矩阵形式

可以得出:

我们设定

很显然可以变为如下:

通过数学归纳法可以推出以下公式:

很显然计算F(n)的值,只需要进行矩阵的n次幂运算,取出结果矩阵第二行第一个元素值即可

这里可以利用快速幂运算求解,假设计算A的N次幂,二阶矩阵的乘法满足结合律

设A,B,C都是任意的二阶矩阵,则

我们设定:

这样可以减少计算次数,因为这里有5个乘, 计算完 得到结果,再乘以 这里用了3个乘

以下是普通数据的快速幂运算,运算改为矩阵乘法,ret改为单位矩阵即可

  1. def qpow(base, exp):
  2. if exp == 0:
  3. return 1
  4. ret = 1
  5. while exp:
  6. if exp & 1:
  7. ret = ret * base
  8. base = base * base
  9. exp >>= 1
  10. return ret

4. 矩阵再推导

我们可以设定:
那么


已知

所以:

计算后可以得出:

这里需要注意一点 n 需要进行奇偶性判定:

所以计算F(N)的值,只需要知道F(n/2+1)和F(n/2)即可

  1. def fib(n):
  2. if n < 1:
  3. return (1, 0)
  4. f_m_1, f_m = fib(n >> 1)
  5. if n & 1:
  6. return f_m_1 * (f_m_1 + 2 * f_m), f_m ** 2 + f_m_1 ** 2
  7. else:
  8. return f_m_1 ** 2 + f_m ** 2, f_m * (2 * f_m_1 - f_m)

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注