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)\) |
以上各方法的时间复杂度
递归:
\(O(2^{n})\) |
迭代:
\(O(n)\) |
矩阵:
\(O(log^{n})\) |
公式:
\(O(1)\) |