斐波那契数列
先来看一组数字: 1, 1, 2, 3, 5, 8, 13, 21, ...,大家发现什么规律了吗?
拆解:
21 = 13 + 8
13 = 8 + 5
8 = 5 + 3
5 = 3 + 2
没错,这就是斐波那契数列,第n项 = n-1项 + n-2项, 第1项和第2项的值为1
计算斐波那契的第30项的值
根据规律,我们第一想法就是递归,代码如下:
function Fib(num){
if(num == 1 || num == 2) return 1;
return Fib(num - 1) + Fib(num - 2);
}
console.log( Fib(30) ); // 832040
是不是感觉很简单,那如果计算Fib(100)呢?
你是不是在等待显示结果? 你的浏览器还有反应吗?赶紧把网页关了吧!
计算斐波那契的第100项的值
为什么浏览器卡死了呢? 因为100项的斐波那契递归,递归太深了,计算Fib(45)都要10s,所以我们还能用递归吗?
我们先来思考一下,计算Fib(100)的步骤
Fib(100) = Fib(99) + Fib(98)
Fib(99) = Fib(98) + Fib(97)
Fib(98) = Fib(97) + Fib(96)
...
我们是不是做了很多重复的事情,能想像Fib(3)被调用了多少次吗? 这就是卡死的原因。
所以,我们把计算过的项存下来,是不是就可以省掉很多重复的递归!
// 缓存
let deepCache = {};
function Fib(num){
if(num == 1 || num == 2) return 1;
// 如果计算过直接返回
if(deepCache[num]) return deepCache[num];
return deepCache[num] = Fib(num - 1) + Fib(num - 2);
}
console.time();
console.log(Fib(100)); // 354224848179262000000
console.timeEnd(); // 0.145751953125ms
我的天,刚才卡死,现在只需要0.1毫秒,这就是缓存的厉害之处
切记:如果递归函数存在重复计算,那么一定要使用缓存!
那这样是不是就无敌了呢? 试一试Fib(10000)
是不是出现了这个:
我的天,这...,栈溢出,怎么办...
递归的层级是有限的,所以遇到这种递归层级特别深怎么办?
不要方,我们知道,大部分递归都可以用循环实现!
计算斐波那契的第1000项的值
根据规律,我们可以用循环实现,代码如下:
function Fib(num){
var fibN_1 = 1;
var fibN_2 = 1;
var result;
for(var i=3; i<=num; i++){
result = fibN_1 + fibN_2;
fibN_2 = fibN_1;
fibN_1 = result;
}
return result;
}
console.time();
console.log(Fib(10000)); // Infinity
console.timeEnd(); // 0.4091796875ms
所以,如果你看过浏览器源码的话,你会发现,很多方法都是用for循环代替递归实现的(比如: js的sort方法)
欢迎评论留言!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。