斐波那契数列实现与其时空复杂度

Fibonacci sequence的定义为F(n) = F(n-1)+F(n-2), 并且F(0)=0, F(1)=1.
即该数列由0和1开始,之后的数字由相邻的前两项相加而得出。
该问题在以兔子繁殖为例时引入

  • 第一个月初有一对刚诞生的兔子
  • 第二个月之后(第三个月初)它们可以生育
  • 每月每对可生育的兔子会诞生下一对新兔子
  • 兔子永不死去
    0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233……

递归

def fibonacci(n):
    assert n >= 0, 'invalid n'
    if n < 2: return n
    return fibonacci(n - 1) + fibonacci(n -2)

时间复杂度

递归方法的时间复杂度为高度为n-1的不完全二叉树节点数,所以近似为

\(O(2^{n})\)

数学求解方法如下:
\(T(n) = T(n-1) + T(n-2) (n>1)\)
设f(n)为参数为n时的时间复杂度
\(f(n) = f(n-1) + f(n-2)\)
转化为求二阶常系数齐次差分方程
设通解为 \(f_{n} = C_{1}f_{n-1} + C_{2}f_{n-2}\)
设有特解 \(f_{n} = \lambda\),λ为非零待定常数,将λ代入方程,易得特征方程 \(\lambda ^{2} = \lambda + 1\)
\(λ = \frac{1\pm \sqrt{5}}{2}\)
再根据 f(0) = 0, f(1) = 1.求出 \(C_{1}\)\(C_{2}\)
得出通项公式 f(n) = \(\frac{1}{\sqrt{5}}[(\frac{1+ \sqrt{5}}{2})^{n} - (\frac{1- \sqrt{5}}{2})^{n}]\)
当n趋于∞时, \((\frac{1- \sqrt{5}}{2})^{n}\) 由于绝对值小于1,所以趋于零。
时间复杂度为 \(O((\frac{1+ \sqrt{5}}{2})^{n})\),约等于 \(O(1.618^{n})\),即指数级复杂度
\(O(2^{n})\)

空间复杂度

递归算法空间复杂度取决于递归的深度,显然为\(O(n)\)

迭代/循环/递推

def fibonacci(n):
    assert n >= 0, 'invalid n'
    if n == 0: return 0
    a, b = 0, 1 
    for _ in range(n - 1): 
        a, b = b, a+b
    return b

时间复杂度

$O(n)$

空间复杂度

\(O(1)\)

矩阵求解

\(F(n)\)\(F(n - 1)\)写成一个2x1的矩阵,然后对其进行变形。
\(\begin{bmatrix}F_{n}\\F_{n-1}\end{bmatrix}=\begin{bmatrix}F_{n-1}+F_{n-2}\\F_{n-1}\end{bmatrix}=\begin{bmatrix}1\times F_{n-1}+1\times F_{n-2}\\1\times F_{n-1}+0\times F_{n-2}\end{bmatrix}=\begin{bmatrix}1 & 1\\ 1 & 0\end{bmatrix}\times\begin{bmatrix}F_{n-1}\\F_{n-2}\end{bmatrix}=...=\begin{bmatrix}1&1\\1&0\end{bmatrix}^{n-1}\times\begin{bmatrix}F_{1}\\F_{0}\end{bmatrix}=\begin{bmatrix}1&1\\1&0\end{bmatrix}^{n-1}\times\begin{bmatrix}1\\0\end{bmatrix}\)
因此要求\(F_{n}\),只要对这个二阶方阵求n - 1次方,最后取结果方阵第一行第一列的数字就可以了。
等式中的矩阵\(\begin{bmatrix}1&1\\1&0\end{bmatrix}\)被称为斐波那契数列的Q-矩阵。
通过Q-矩阵,我们可以利用如下公式进行计算:
\(F_{n}=(Q^{n-1})_{1,1}\)
如此一来,计算斐波那契数列的问题就转化为了求Q的n−1次幂的问题。
\(A^{n}=\left\{\begin{matrix}A\cdot (A^{2})^{\frac{n-1}{2}},\,if\, n\, is\, odd\\ (A^{2})^{\frac{n}{2}},\,if\, n\, is\, even\end{matrix}\right.\)
可见时间复杂度满足\(T(n) = T(n / 2) + O(1)\)
Master定理可得

时间复杂度

$O(log^{n})$

空间复杂度显然为

\(O(1)\)

from numpy import matrix

def MatrixPower(mat, n):
  assert n > 0, 'invalid n'
  res = None
  temp = mat
  while True:
    if n & 1:
      if res is None: res = temp
      else: res = res * temp
    n >>= 1
    if n == 0: break
    temp = temp * temp
  return res

def fibonacci(n):
  assert n >= 0, 'invalid n'
  if n < 2: return n  # F(0) = 0, F(1) = 1
  mat = matrix([[1, 1], [1, 0]], dtype=object)
  mat = MatrixPower(mat, n - 1)
  return mat[0, 0]

通项公式法

from zhihu.com

def fibonacci(n):
    root_Five = 5**0.5
    result = (((1 + root_Five) / 2)**n - ((1 - root_Five) / 2)**n) / root_Five
    return int(result)

显然,该方法的

时空复杂度

均为

\(O(1)\)
, 但使用公式计算的方法由于有大量的浮点运算,在n增大时浮点误差不断增大会导致返回结果不正确甚至数据溢出。
以上各方法的时间复杂度
递归
\(O(2^{n})\)

迭代
\(O(n)\)

矩阵
\(O(log^{n})\)

公式
\(O(1)\)

参考链接

五种方法计算斐波那契数列的第n项
计算斐波纳契数,分析算法复杂度

猜你喜欢

转载自www.cnblogs.com/yexuesong/p/9166754.html
今日推荐