算法小练习之斐波那契数列浅析

  • 常见实现代码:

以下代码均为Java8实现

public class Main {
    public static void main(String[] args) {
        int fib = fib(10);
        System.out.println(fib);//55
    }
	// 具体实现
    static int fib(int N) {
        if(N == 1 || N== 2){
            return 1;
        }else{
            return fib(N-1)+fib(N-2);
        }
    }
}

但是这种实现形式性能效率极其低下:如获取fib(10),你需要获取fib(9)和fib(8),而在获取fib(9)的时候又需要去获取fib(8),导致存在大量重复计算,时间复杂度O(2^n)。

  • 改进实现1-1:使用一个存储媒介(备忘录),把已计算的值存储,需要时则直接获取
public class Main {
    static List<Integer> memo;
    public static void main(String[] args) {
        int fib = fib(10);
        System.out.println(memo);//[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
        System.out.println(fib);//55
    }

    //自顶向下
    static int fib(int N) {
        if (N < 1) {
            return 0;
        }
        // 备忘录,容量为N+1,全初始化为 0
        memo = new ArrayList<>(Collections.nCopies(N+1, 0));
        // 进行带备忘录的递归
        return helper(memo, N);
    }

    static int helper(List<Integer> memo, Integer n) {
        if (n == 1 || n == 2){
            memo.set(n,1);
            return 1;
        }
        // 已经计算过则直接获取值
        if (memo.get(n) != 0){
            return memo.get(n);
        }
        memo.set(n,helper(memo, n - 1) + helper(memo, n - 2));
        return memo.get(n);
    }
}

在改进1-1中使用的是自顶向下法,即fib(10)->fib(9)…
也可以使用自底向上法实现

  • 改进1-2:通过fib(1)=fib(2)=1,直接递归设置值到存储媒介中,获取对应值则从媒介中获取
public class Main {
    static List<Integer> memo;
    public static void main(String[] args) {
        int fib = fib(10);
        System.out.println(memo);
        System.out.println(fib);
    }

    //自底向上
    static int fib(int N) {
        if (N < 1) {
            return 0;
        }
        // 备忘录,容量为N+1,全初始化为 0
        memo = new ArrayList<>(Collections.nCopies(N+1, 0));
        // 进行带备忘录的递归
        if (N == 1 || N == 2){
            return 1;
        }
        memo.set(1,1);
        memo.set(2,1);
        for (int i = 3; i <= N; i++) {
            memo.set(i,(memo.get(i-1)+ memo.get(i- 2)));
        }
        return memo.get(N);
    }
}

自底向上和自顶向下都不需要重复计算,所以大大提高了效率,时间复杂度O(n);

  • 改进1-3:为简化代码,降低空间复杂度,我们也可以如此实现
public class Main {
    public static void main(String[] args) {
        int fib = fib(10);
        System.out.println(fib);
    }

    //状态压缩
    static int fib(int N) {
        if (N < 1) {
            return 0;
        }
        int prev = 1, curr = 1;

        for (int i = 3; i <= N; i++) {
            int sum = prev + curr;
            prev = curr;
            curr = sum;
        }
        return curr;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值