优化斐波那契数列递归的计算

这段时间我在系统的学习一下算法4,并计划学完每一章遍写一个总结,期间遇到的一些问题和思路我也想分享给大家。希望前行的路上我们一起加油!

斐波那契数列指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(≥ 3,∈ N*)

第一个递归是根据函数得到的最直观的一个

private static long F(int N) {
        times++;//用于计算执行函数次数
        if (N == 0) return 0;
        if (N == 1) return 1;
        return F(N - 1) + F(N - 2);
    }

我们声明一个静态量times来计算函数执行的次数,也就是递归调用的次数+1;

我们计算12组值,并列举出来:

N: 0 0 || times: 1
N: 1 1 || times: 1
N: 2 1 || times: 3
N: 3 2 || times: 5
N: 4 3 || times: 9
N: 5 5 || times: 15
N: 6 8 || times: 25
N: 7 13 || times: 41
N: 8 21 || times: 67
N: 9 34 || times: 109
N: 10 55 || times: 177
N: 11 89 || times: 287
N: 12 144 || times: 465

通过观察我们会发现运行次数为f(n+2) = f(n+1) + f(n) + 1;和斐波那契数的增长是一样的

我们可以通过数学的方式计算出斐波那契数列的通项公式:

算出其时间复杂度约为O(2^n),指数增长级别。

现在列出两个方法可将其复杂度降至O(n):

1,添加一个数组来存储先前的数据,当你计算出f(0),f(1)的值,便将其存入一个数组之中(牺牲空间换取时间),比如你要算f(2),那么就在数组里面拿到f(1)和f(0)的值,同时在数组里存入f(2):

  private static long getF(int N) {
        long[] f = new long[N + 1];//用一个数组去进行一个缓存
        return F(N, f);
    }
    private static long F(int N, long[] f) {
        times++;
        if (f[N] == 0) {
            if (N == 1)
                f[N] = 1;
            else if (N > 1)
                f[N] = F(N - 1, f) + F(N - 2, f);
        }
        return f[N];
    }

2,运用迭代的思想,每次计算缓存当前两个数的值,可以较如上方法可以降低空间复杂度:

  public static long FBetter(int N) {
        long ahead1 = 0;
        long ahead2 = 1;
        long ahead3 = ahead1 + ahead2;
        for (int i = 2; i <= N; i++) {
            ahead1 = ahead2;
            ahead2 = ahead3;
            ahead3 = ahead1 + ahead2;
        }
        return ahead3;
    }

 

posted @ 2020-04-09 10:58  junlancer  阅读(432)  评论(0编辑  收藏  举报