斐波拉契数Fibonacci,递归,备忘录,DPtable,优化空间

本文介绍四种不同实现方式的斐波拉契数列算法:暴力递归、备忘录、DP表及优化存储空间方案。通过对比分析,探讨各种方法的时间与空间复杂度,帮助读者理解算法优化的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

求斐波拉契数

斐波拉契数为,Fib(N) = Fib(N-1)+Fib(N-2) F(0)=F(1)=1 用Java编写能求Fib(N)的程序 输入为N,须输出Fib(N)
如输入:
3
输出:

3

注意:问题比较容易出在sn的类型上面,用long一般就没问题,用double或者int可能会在某些测试平台上无法得到满分

public class Fibonacci {
    public static void main(String[] args) {
        // 1、暴力递归
        long start1 = System.currentTimeMillis();
        System.out.println(fib(40));
        long end1 = System.currentTimeMillis();
        System.out.println("暴力递归时间:" + (end1 - start1));


        // 2、备忘录
        long start2 = System.currentTimeMillis();
        System.out.println(fibHelper(40));
        long end2 = System.currentTimeMillis();
        System.out.println("备忘录时间:" + (end2 - start2));

        // 3、dpTable
        long start3 = System.currentTimeMillis();
        System.out.println(dpTable(40));
        long end3 = System.currentTimeMillis();
        System.out.println("备忘录时间:" + (end3 - start3));

        // 4、lessSpace
        long start4 = System.currentTimeMillis();
        System.out.println(lessSpace(40));
        long end4 = System.currentTimeMillis();
        System.out.println("备忘录时间:" + (end4 - start4));
    }

    // 暴力递归
    public static double fib(int n) {
        if (n == 0) return 0;
        if (n == 1 || n == 2) return 1;
        return fib(n - 1) + fib(n - 2);
    }

    // 备忘录
    public static double fibHelper(int n) {
        if (n == 0) return 0;
        double[] memo = new double[n + 1];
        return helper(memo, n);
    }

    public static double helper(double[] memo, int n) {
        if (n == 1 || n == 2) return 1;
        if (memo[n] != 0) return memo[n];
        memo[n] = helper(memo, n - 1) + helper(memo, n - 2);
        return memo[n];
    }

    // DP table
    public static double dpTable(int n) {
        if (n == 0) return 0;
        if (n == 1 || n == 2) return 1;
        double[] dp = new double[n + 1];
        dp[1] = dp[2] = 1;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }

    // 优化存储空间方案
    public static double lessSpace(int n) {
        if (n == 0) return 0;
        if (n == 1 || n == 2) return 1;
        double before = 1, total = 1;
        for (int i = 3; i <= n; i++) {
            double sum = before + total;
            before = total;
            total = sum;
        }
        return total;
    }
}

 

计算结果:

1.02334155E8
暴力递归时间:353
1.02334155E8
备忘录时间:0
1.02334155E8
DPtable时间:0
1.02334155E8
优化空间时间:0

进阶:

上面的暴力递归,时间复杂度=O(2^n),空间复杂度=O(1),可以清楚得看见时间上暴力递归比另外三种的差距,如果你的计算数据再大一点,暴力递归将会花费更多的时间。

如果我们使用备忘录或者dp table,就可以将时间复杂度降低到O(n),但是空间复杂度将变为O(n),从时间复杂度上面,已经可以算得上是降维打击了,毕竟CPU可比内存贵多了。

这两者的区别是前者是自顶向上,后者是自底向上计算。

把备忘录独立出来,就成了dp table。dp table省掉了一个递归,从代码上面来说更加简洁。

第四种方法,我们不难从dp table可以看出,我们只需要记录当前数值,和前面两个数值就可以了,并不需要把所有的数据都记录下来。肉眼可见得我们又将空间复杂度变为了O(1),时间复杂度依然是O(n),岂不美哉。
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值