递归与迭代 | 求斐波那契数列第n项值的四种算法

前言:

昨儿晚上三点多睡不着,不知道胡思乱想了些啥,好不容易睡着了又做了些稀奇古怪的梦。考研还是继续,真难。

这一篇博客记录一下求斐波那契数列第n项值得几种方法,用到了递归和迭代的方法,所以首先我们来区分一下递归和迭代,再来记录几种方法。

递归和迭代

联系

递归与迭代都是循环的一种。

区别

1、程序结构不同

  • 递归是重复调用函数自身的循环。
  • 迭代是函数内部代码的循环。
  • 注意:迭代和普通循环的区别:迭代时,循环代码中参与计算的变量也是要返回的结果,当前保存的结果作为下一次循环计算的初始值。

2、算法结束方式不同

  • 递归是在遇到满足终止条件的情况时结束循环。
  • 迭代是使用计数器结束循环。
  • 注意:很多情况会采用多种循环混合采用。

3、效率不同

  • 在循环的次数较大时,迭代的效率明显高于递归。

求斐波那契数列第n项值

递归方法:

思想:

利用斐波那契数列计算公式f(n) = f(n-1) + f(n-2),递归调用函数自己。时间复杂度为O(2^n)。

代码:

    // 斐波那契数列--递归:O(2^n)
    function fib(n) {
        if(n<2) {
            return n;
        }
        return fib(n-1) + fib(n-2);
    }
    console.log(fib(8));

注意:

此段代码中if(n<2) {return 0;}其实不够严谨,因为这样的话即使传入参数n为负数(如-1)也会返归n,在没有严格规定实参必须为非负整数的情况下,最好还是写成if(n == 0) return 0; if(n == 1) return 1;

递归方法优化:

思想:

上述递归的方法,每一次执行到f(n-1)和f(n-2)时都要重新计算一遍,还要开辟新的空间来保存它们,比较浪费空间,可以优化为:开辟一个缓存区,存放计算过的每一个值,下一次用到时直接从缓存区查找,找不到则再计算,如此,可以减少空间上的浪费。

代码:

    // 优化递归--结构体当缓存区
    function fib1(n) {
        const cache = {
            '0': 0,
            '1': 1
        }
        function helper(n) {
            if(n in cache) return cache[n];
            const res = helper(n-1) + helper(n-2);
            cache[n] = res;
            return res;
        }
        return helper(n);
    }
    console.log(fib1(8));

迭代方法:

思想:

此方法的思路是将每一项计算出来的f(n)存入数组,使用迭代的方法,每一次迭代完成,数组中就多了一项元素。

此处存疑?

上面说到,迭代是循环中参与计算的变量就是要返回的变量,而我的代码这里参与计算的是数组,返回的却是数组的第n项,不知道这个算不算是正宗的迭代。

代码:

    // 迭代:O(n)
    function fib2(n) {
        let arr = [0, 1];
        for (let i = 2; i<=n; i++) {
            arr.push(arr[i-1] + arr[i-2]);
        }
        return arr[n];
    }
    console.log(fib2(8));

迭代方法优化:

思想:

上一段代码中,随着n的值的增大,数组会无限变长,而我们知道斐波那契数列是无穷的,所以当n值很大时,就对空间浪费巨大。反正计算新的值时也就只会用到它的前两个值,每一次从末尾推入一个新元素,就同时从开头删去一个元素,让数组的长度始终只用保存两个元素,大大减少了空间的使用。

代码:

    // 优化迭代--保持数组长度总是为2,节约空间
    function fib3(n) {
        let arr = [0, 1];
        if(n == 0) return 0;
        if(n == 1) return 1;
        for (let i = 2; i<=n; i++) {
            // 分成两步实现
            /* // 将0号元素从数组删除
            let one = arr.shift();
            // 添加新的元素
            arr.push(one + arr[0]); */

            // 一步实现
            arr.push(arr.shift() + arr[0]);
        }
        return arr[1];
    }
    console.log(fib3(0));

小结

不知道干什么的时候就学习,不管是往哪个方向学,学习总是没错的。

学习递归与迭代参考的博客是http://blog.csdn.net/daijin888888/article/details/70157153

学习斐波那契数列第n项值的算法是参考了B站视频https://www.bilibili.com/video/BV1aE41147Ly

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值