JavaScript版《剑指offer》刷题(7)斐波那契数列及其优化

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

http://www.thisjs.com/2017/09/21/my-view-of-fibonacci/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值