斐波那契数列
相信每一个接触算法的人都会遇到一道经典的算法问题,斐波那契数列。
斐波那契数列的规律也很简单,就是第一第二项值为1,第三项开始每一项值为该项前两项的和;实现起来也并不难。
function fib(n){
if (n===1 || n===2){//判断项所在位置,如果为第一第二项,返回1
return 1;
} else{
return fib(n-1)+fib(n-2);//位置在第三项及以后,返回前两项和
}
}
console.log(fib(5));
这个就是在JS里面简单实现求斐波那契数列某一项值的一个代码;
但是这个代码的缺陷也是很明显的,时空复杂度太高;我们可以定义一个变量 i 来看一下
let =0;
function fib(n){
i++;
if (n===1 || n===2){//判断项所在位置,如果为第一第二项,返回1
return 1;
} else{
return fib(n-1)+fib(n-2);//位置在第三项及以后,返回前两项和
}
}
console.log(fib(5));
console.log(i);
在这个图片里面我们可以看到,当n的值为40的时候,i 的值是204668309,也就是说我们求斐波那契第40项的时候函数被调用的次数;
因为字符串的不可变特征只要还没找到函数出口前就会一直在栈上开辟新空间去存储数据,这个也是栈溢出最主要的原因。
优化
有问题那么我们就要去优化,最主要的性能问题就是数据存储上会不断开辟新空间造成空间复杂度的提升,解决方法也很简单:定义一个空数组存储斐波那契数列项。因为数组是一个复杂类型存储在堆里面,而且需要new的时候才会去创建一个新的存储空间,我们只需要在栈上建立一个索引去访问该数组就可以。
//定义存储斐波那契数列项数组
let result = [];
let i=0;
function sum(a) {
i++;
//首先判断数组内有没有当前斐波那契数列项,如果有直接从数组获取;没有则将该项push进数组,再从数组过去该项
if (result[a] !== undefined){
return result[a];
} else{
if (a===1 || a===2){
result[a] = 1;
return 1;
} else{
result[a] = sum(a-1)+sum(a-2);
return result[a];
}
}
}
console.log(sum(1476));
console.log(i);
上面代码就是经过优化之后的代码,很简单;就是添加了一个数组存储斐波那契数列项。效果也是很显著;
下面是求第1476项 i 的值:
上面就是斐波那契数列求项的实现以及优化代码