斐波那契数列

从 斐波那契 数列 入门动态规划

什么是斐波那契数列?

假设斐波那契数列用 F 来表示, 那么 F(0)=1, F(1)=1, 且当 n>=2 时:F(n)=F(n-1)+F(n-2)。

比如计算 F(4), 可以用下面这幅图来表示:

计算 F(4),需要向下计算 F(3) 和 F(2), 而计算 F(3) 又需要计算 F(2) 和 F(1)。可以看到 F(2) 被重复计算了。假设 计算 F(n) 的 n 很大,那么将有大量的中间数据被重复计算。那么如果我们用额外的一个数组去存储已经被计算过的变量,则会避免上述说的冗余计算。

什么是动态规划?

将一个大问题将拆分成许多重叠的在子问题,在求解子问题的过程中保留子问题的答案,使得每一个子问题只求解一次,最终获得原问题的答案。这就是动态规划。

一般动态规划有两种求解思路,一种是自顶向下解决,另一种是自顶向上解决。由于不涉及重复计算,所以两种思路的时间复杂度和空间复杂度均相同。一般来说,自顶向下的求解思路更加自然和容易被想到。

自顶向下求斐波那契数列

 //自顶向下递归, 使用记忆化搜索进行剪枝
public class FibonacciSeq {

    int[] memo;//用来存储已经计算好了的斐波那契数列

    FibonacciSeq(int n){
        memo=new int[n+1];
        for (int i = 0; i < memo.length; i++) {
            memo[i]=-1;
        }
    }

    public int fib(int n){
        if (n==0){
            return 0;
        }
        if (n==1){
            return 1;
        }

        if (memo[n]==-1){
            memo[n]=fib(n-1)+fib(n-2);
            return memo[n];
        }else {
            return memo[n];
        }
    }

    public static void main(String[] args) {
        int n=50;
        FibonacciSeq fbsq=new FibonacciSeq(n);

        long startTime=System.nanoTime();
        fbsq.fib(n);
        long endTime=System.nanoTime();
        double time=endTime-startTime;

        System.out.println("fib"+n+"花费时间"+time/1000000000.0+"秒");
    }


}

自底向上求斐波那契数列


// 自底向上解决问题
public class FibonacciSeq2 {

    int[] memo;//用来存储已经计算好了的斐波那契数列

    public int fib(int n){
        memo=new int[n+1];

        memo[0]=0;
        memo[1]=1;

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

        return memo[n];
    }

    public static void main(String[] args) {
        int n=50;
        FibonacciSeq2 fbsq=new FibonacciSeq2();

        long startTime=System.nanoTime();
        fbsq.fib(n);
        long endTime=System.nanoTime();
        double time=endTime-startTime;

        System.out.println("fib"+n+"花费时间"+time/1000000000.0+"秒");
    }

}

经过运行发现,无论是自顶向下还是自底向上,运行的时间都没有明显的区别。

Last updated

Was this helpful?