算法:斐波那契数

49 阅读2分钟

这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

背景

学习前端三个月了,准备刷刷面试题,总结总结,一天几道面试题,向大厂进军。

问题

斐波那契数

计算斐波那契数

如斐波那契数,通常用F(n)表示,形成的序列成为 斐波那契数列。该数列由0和1开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2),其中n>1。

给你n,计算F(n)

示例1:

输入: 2 输出: 1 解释: F(2)=F(1)+F(0)=1+0=1;

示例2:

输入: 3 输出: 2 解释: F(3)=F(2)+F(1)=1+1=2;

解析: 看到这里,大家是不是以为,这种题也太简单了吧,还搞个复杂的名字“斐波那契数”,分分种给它搞定,直接递归不就行了,于是有了下面的代码:

    /**
     * @param {number} n
     * @return {number}
     */
    var fib = function(n) {
        return n <= 1 ? n : fib(n - 1) + fib(n - 2);
    };

验证结果:

image.png

简单不简单,一行代码搞定了,难道就这样结束了,这公司是傻了吗?考这种题。

搞了半天,小丑竟是我自己。

来看看另外一种实现思路:动态规划-数组滚动

名字一听就比较高大上,我赶紧问问度娘这是啥意思!

动态规划有一个很重要的特点:无后效性,意思是当前状态的决策不受过去决策的影响。所以当状态很多时,我们不必去保存所有的状态,这样很占用内存,我们只需保存与当前决策有关的状态即可。

通俗易懂的意思就是节省内存,只保留必要的空间。

那我们再回过头来看看这道题:

  1. 条件边界是F(0)=0,F(1)=1。 当n>1时,f(n)=f(n-1)+f(n-2),相当于前两项的和。
  2. 根据这种理论,我们只需要数组遍历的时候,动态保存上两次的值,不就可以了吗?

图解:

image.png

来看看代码实现:

/**
 * @param {number} n
 * @return {number}
 */
var fib = function(n) {
    if(n===0) return 0;
    if(n===1) return 1;
    //初始化默认值
    //p=0  //F(-1)设置为0
    //q=0   //F(0)=0
    //r=1   F(1)的结果
    var p=1,q=0,result=1;
    for(let i=2;i<=n;i++){
        p=q;
        q=result;
        result=p+q;
    }
    return result;
};

对比:第一种和第二种的方案

image.png

可以看到执行时间不同,第一种方案明显多执行了很多次数!

比如F(4)=f(3)+f(2);第一种方案:f(2)又重新计算了!

结语

一步一步慢慢来,踏踏实实把活干!