费波那契数列 (Fibonacci sequence) 定义:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2), n >= 2
数列由 0 和 1 开始,之后的费波那契系数就是由之前的两数相加而得出。其中,0 不是第一项,而是第零项。
斐波那契数列:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
计算第 n 斐波那契数,即给定 n
,计算 F(n)
。
Example:
Input: n = 4
Output: 3
Explanation: F(4) = F(3) + F(2) = 2 + 1 = 3.
编号 | 解法 | Approach |
---|---|---|
1 | 递归 | Recursion |
2 | 自底向上进行迭代 | Iterative Top-Down Approach |
3 | 数学公式 | Math |
4 | 矩阵求幂 | Matrix Exponentiation |
fibonacci-recursive.js
const fibonacci = (n) => {
let [a, b] = [0, 1];
for (let i = 2; i <= n; i += 1) {
[a, b] = [b, a + b];
}
return n < 2 ? n : b;
};
时间复杂度 | 空间复杂度 |
---|---|
O(2^n) | O(n) |
fibonacci-iterative.js
const fibonacci = (n) => {
let [a, b] = [0, 1];
for (let i = 2; i <= n; i += 1) {
[a, b] = [b, a + b];
}
return n < 2 ? n : b;
};
时间复杂度 | 空间复杂度 |
---|---|
O(n) | O(1) |
构建以下递推关系:
因此,只要计算矩阵 M 的 n 次幂,就可以得到 F(n) 的值。可以使用快速幂算法来加速计算矩阵 M 的 n 次幂。
fibonacci-math.js
const mul = (x, y) => [
[
x[0][0] * y[0][0] + x[0][1] * y[1][0],
x[0][0] * y[0][1] + x[0][1] * y[1][1],
],
[x[1][0] * y[0][0] + x[1][1] * y[1][0], x[1][0] * y[0][1] + x[1][1] * y[1][1]],
];
const pow = (x, n) => {
let r = [[1, 0], [0, 1]];
let v = x;
while (n) {
if (n % 2 === 1) {
r = mul(r, v);
n -= 1;
}
v = mul(v, v);
n /= 2;
}
return r;
};
const fibonacci = (n) => (n <= 0
? 0
: mul(
[[0, 1], [1, 0]],
pow([[0, 1], [1, 1]], n - 1),
)[0][1]);
时间复杂度 | 空间复杂度 |
---|---|
O(log n) | O(1) |
根据斐波那契数 F(n) 齐次线性递推,得:
求解:
带入 F(0)=0,F(1)=1,求解得:
因此,斐波那契通项公式:
要注意的是,由于通项公式计算过程中的根号计算会导致精度损失,所以返回结果需要进行取整操作
fibonacci-matrix.js
const fibonacci = (n) => Math.round(
(
((1 + Math.sqrt(5)) / 2) ** n - ((1 - Math.sqrt(5)) / 2) ** n
)
/ Math.sqrt(5),
);
Math.sqrt 函数的时空复杂度与 CPU 支持的指令集相关,本文不做详解。