聊聊斐波那契数列中递归的重复计算

聊聊斐波那契数列中递归的重复计算

聊聊斐波那契数列中递归的重复计算

所谓的斐波纳契数列是指:

前2个数是 0 和 1 。
第 i 个数是第 i-1 个数和第i-2 个数的和。
斐波纳契数列的前10个数字是:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ...

1 递归实现

根据定义,很快就能写出递归实现:

public int fibonacci(int n) {
    if (n < 2) {return 0;}
    if (2 == n) {return 1;}

    return fibonacci(n - 1) + fibonacci(n - 2);
}

但是,这个函数去执行的时候,会发现非常的慢。那是什么原因呢?
我们仔细观察一下,每一次递归的时候,我们都会调用两个,所以,计算时,从n、n-1、… 0会是一个金字塔,二叉树的分布,也就是靠近0的底层,会有2^n次运算,就是一个指数级运算,计算时间复杂度为O(2^n),运算速度是非常慢的。
原因是什么呢?假如,我们计算的是10,那么它相应的要计算 9 + 8,而9要计算 8 + 7, 8又要计算 7 + 6.相当于越往底层去,计算的次数越多。

    10
   /  \
  9    8
 / \  / \
8   7 7  6
    ...

2 递归改进

那么避免重复计算的方法就是,每计算得到一个值,便用一个数组保存这个值,下次计算该值的时候直接引用就可以了。

public int fibonacci(int n) {
    int[] array = new int[n + 1];

    if (n < 2) {return 0;}
    if (2 == n) {return 1;}
    array[1] = 0;
    array[2] = 1;

    return helper(array, n);
}

private int helper(int[] array, int n) {
    if (n < 2) {
        return 0;
    }
    if (2 == n) {
        return 1;
    }
    array[n] = helper(array, n - 1) + array[n - 2]; // 保存每次计算的结果
    return array[n];
}

但这种方法不是尾递归的,所以,调用栈内存会比较多。

3 迭代法

用迭代法来计算是最简单,速度也最快的。

public int fibonacci(int n) {
    int[] array = new int[n + 1];

    if (n < 2) {return 0;}
    if (2 == n) {return 1;}
    array[1] = 0;
    array[2] = 1;

    for (int i = 3; i <= n; i++) {
        array[i] = array[i - 1] + array[i - 2];
    }

    return array[n];

}

Date: 2017-07-02 10:55

Author: WEN YANG

Created: 2017-07-02 Sun 13:01

Emacs 25.2.1 (Org mode 8.2.10)

Validate

posted @ 2017-07-02 13:02  yangwen0228  阅读(1652)  评论(0编辑  收藏  举报