1.题目描述
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
n<=39
2.题目分析
我们都知道斐波那契可以用递归,但是递归重复计算的部分太多了(虽然可以通过),但是这道题更应该用动态规划来做,
动态规划的特点是:最优子结构、无后效性、子问题重叠。话不多说,直接上代码
3.代码
function Fibonacci(n) {
// write code here、
let f = 0,
g = 1;
while (n--) {
g += f;
f = g - f;
}
return f;
}
动态规划更多可以参考:
https://segmentfault.com/a/1190000015489981#articleHeader1
https://segmentfault.com/a/1190000007927865
https://segmentfault.com/a/1190000007115162#articleHeader4
我们再来看非递归优化、尾递归优化和非递归实现
/*
题目:
求斐波那契数列的第n项
要求:
写一个函数,输入n,求斐波那契数列数列的第n项。
*/
//非为递归优化
function fib(n) {
if(n <= 0) return 0;
if(n === 1) return 1;
return fib(n - 1) + fib(n - 2);
}
//尾递归优化,值调用函数本身,不会有其他运算
function fib2(n, pre = 0, current = 1) {
if(n <= 0) return pre;
if(n === 1) return current;
//pre = current;
//current = pre + current;
return fib2(n - 1, current, pre + current);
}
//非递归实现
function fib3(n) {
if(n <= 0) return 0;
if(n === 1) return 1;
let pre = 0,
current = 1,
temp = 0,//临时变量保存pre值,不然会被更新
i = 2;
while(i <= n) {
temp = pre;
pre = current;
current = temp + current;
++i;
}
return current;
}
console.log(fib3(10))
尾调用原理
尾调用是指函数执行的最后一步是调用另一个函数。如果满足以下条件,则尾调用不再创建新的帧栈,而是清除并重用当前帧栈。
1.尾调用不访问当前帧栈的变量(也就是说函数不是一个闭包)
2.在函数内部,尾调用是最后一条语句
3.尾调用的结果作为函数值返回
这样,满足上面三个条件,可以被Javascript引擎自动优化。
所以,一般形式如下:
function a() {
...
return b()
}
最后一步一定返回 b(),如果返回1+ b(),都不能被引擎优化。
看过你不知道的javascript那3本书,你可能知道函数调用的原理:函数调用会在内存形成一个“调用记录”,又称“调用帧”,保存调用位置和内存变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,依次类推。所有的调用帧,就形成一个“调用栈”。
所以,尾调用具体原理:尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就可以了。
如上面的例子,正常function a 里调用b,a是b的外层函数,等程序运行到b内部的时候,a的调用帧还会保留,这样普通的递归,会保留很多帧,最后导致内存溢出(具体浏览器或Node最大的堆栈大小不清楚…)。而尾调用由javascript引擎优化,a返回了b,a的调用帧直接被b的调用帧替代,如此,整个调用栈只保留一条,永远不可能溢出。
尾调用更多理解可以参考:
https://imweb.io/topic/584d33049be501ba17b10aaf
https://segmentfault.com/a/1190000014747296#articleHeader3
https://imweb.io/topic/5a244260a192c3b460fce275
参考文章:
https://www.cnblogs.com/wuguanglin/p/Fibonacci.html
https://github.com/DavidChen93/-offer-JS-/blob/master/10.1 斐波那契数列.js
https://blog.csdn.net/qq_35800306/article/details/80623972
https://www.cnblogs.com/echovic/p/6430646.html