zoukankan      html  css  js  c++  java
  • 斐波那契数列的几种解法

    斐波那契数列一般都用于介绍递归的思想。

    我们知道斐波那契数列的通项公式(n>1)如下:

    F(n) = F(n-1) + F(n-2)

    按照这个公式写个代码就很容易了:

    int fibonacci(int n) {
        if (n == 0 || n == 1) {
            return n;
        }
        return fibonacci(n-1) + fibonacci(n-2);
    }
    

    这种代码简单又优雅,但是缺点也很明显,就是慢:

    又慢又占空间。

    这是为什么呢?

    我们来看看递归都做了什么,以n=5为例,如下图:

    这里会有很多的重复计算过程,这个重复计算的过程叫做递归栈,递归最大的毛病就是递归栈里重复的东西太多。

    观察上图,如果从下向上,效果会更加的好,可以借助数组来实现,我们知道斐波那契数列其实就是这样的一个数列:

    0,1,1,2,3,5,8...

    只要将第一和第二项算出来保存在数组中,后面的项就很好计算了:

    public int Fibonacci2(int n) {
            int[] fib = new int[45];
            fib[0] = 0;
            fib[1] = 1;
            for (int i = 2; i <= n; i++) {
                fib[i] = fib[i - 1] + fib[i - 2];
            }
            return fib[n];
        }
    

    n=5的时候,这个数组最终是这样的[0,1,1,2,3,5,......],此时的时间复杂度仅仅是O(n),比递归的O(2^n)好太多了:

    仅仅消耗了17ms,是原先的5.8%左右。

    但是,继续观察上面的数组:

    [0, 1, 1, 2, 3, 5],我们会发现这个数组中,f(0)和f(2)并没有用到,这两个其实可以精简掉,于是代码变成了这样:

    public int Fibonacci(int n) {
            if (n == 0 || n == 1) {
                return n;
            }
            int a = 0;
            int b = 1;
            int c = 0;
            for (int i = 2; i <= n; i++) {
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    

    n=5的情况下,这个循环只会计算f(1),f(3),f(4)和f(5)的值,并不用数组去保存,因此空间也节省了下来。

    另外我试了试C和Java语言用第三种解法的速度差异,发现C语言还是很有优势的:

    同样的算法竟然只用了5ms。

  • 相关阅读:
    2020年秋招三星面试题
    物联网金融和互联网金融的区别与联系
    数据库事务的4种隔离级别
    Access-cookie之sqlmap注入
    SDL-软件安全开发周期流程
    图片马的制作
    ssrf内网端口爆破扫描
    逻辑漏洞_验证码绕过_密码找回漏洞
    平行越权与垂直越权
    xff注入
  • 原文地址:https://www.cnblogs.com/wingsless/p/15135453.html
Copyright © 2011-2022 走看看