如何优雅的解决斐波那契数列
程序员文章站
2024-03-19 19:26:52
...
如何优雅的解决斐波那契数列
斐波那契数列是一个出镜率极高,这个问题非常有意思,它看似简单,其实里面有很多的门道,从最初级的程序员到算法高手,都能写出来答案,那么我们尝试去研究下它的“最叼”解。
常见的解法以及分析
- 时间复杂度:O(n^2)
let fibnacci = n =>
n <= 0 ? 0 : n == 1 ? 1 : fibnacci(n-2) + fibnacci(n-1);
将递归
改为动态规划
- 时间复杂度:O(n)
let fibnacci = n => {
if(n == 0) return 0p;
let a1 = 0, a2 = 1;
for(let i = 1; i < n; i++){
[a1, a2] = [a2, a1+a2];
}
return a2;
}
更好的解法?
数学思想——通项公式
let fibnacci = n =>
(Math.pow((1 + Math.sqrt(5))/2, n) - (Math.pow(1 - Math.sqrt(5))/2, n)) / Math.sqrt(5)
注意!通项公式使用了内置函数 Math.pow,它的时间复杂度并不低,思路上是正确的,我们就从实现上改一改
自己实现一个Math.pow() ——让幂运算的时间复杂度是无限接近 O(log(n))
let pow = (x ,y) => {
var r = 1;
var v = x;
while(n) {
if(n % 2 == 1){
r *= v;
n-=1
}
v = v * v;
n = n / 2
}
return r;
}
此外这个实现方式有一些瑕疵,需要取整
利用矩阵的方式求斐波那契数列
矩阵乘法(此时不得不感叹大学里学的线性代数都还给老实了。。。)
我们将这种数学思想实现的pow方法整理一下
let matrix22_pow = (x, n) => {
var r = [[1, 0][0, 1]]
var v = x
while(n){
if(x % 2 == 1) {
r = matrix_mul(r, v)
n -= 1;
}
v = matrix_mul(v, v)
n = n / 2
}
return r
}
在将次pow方法套用到斐波那契数列的解法中
最终解
let fibnacci = n =>
n <= 0 ? 0 :
matrix_mul( [[0, 1],[0, 0]] , matrix22_pow([[0, 1],[1, 1]], n-1) )[0][1]