動態規劃、回溯、貪心,分治

動態規劃篇算法

  • 從斐波那契數列開始

咱們先給出斐波那契數列的經常使用算法類緩存

public class Fibonacci {
    private static int num = 0;
    private Fibonacci() {
    }
    public static int fib(int n) {
        num++;
        if (n == 0) {
            return 0;
        }
        if (n == 1) {
            return 1;
        }
        return fib(n - 1) + fib(n - 2);
    }

    public static void main(String[] args) {
        num = 0;
        int n = 20;
        long start = System.nanoTime();
        int res = Fibonacci.fib(n);
        long end = System.nanoTime();
        System.out.println(res);
        System.out.println((end - start) / 1000000000.0);
        System.out.println(num);
    }
}

運行結果spa

6765
3.96599E-4
21891blog

此時咱們調大n的值爲40ci

運行結果get

102334155
0.473162902
331160281class

再調大n的值爲42List

267914296
1.302307318
866988873搜索

咱們能夠看到此處隨着n的增大,時間是幾何倍數增加,由此咱們可知斐波那契數列的時間複雜度爲O(2^n)im

但咱們發現斐波那契數列的存在着大量的重複計算,以下圖所示,咱們來看計算一個n=5的時候都有哪些重複計算的地方

在這裏咱們能夠看到3被計算了2次。

而2則被計算了3次,這仍是n = 5的狀況下,若是隨着n值的增大,重複計算的次數就會愈來愈多。

因此咱們給出了一個新的記錄重複計算值不須要從新計算的斐波那契算法類

public class Fibonacci {
    private static int num = 0;
    private static List<Integer> memo = new ArrayList<>();
    private Fibonacci() {
    }
    //記憶化搜索
    public static int fib(int n) {
        num++;
        if (n == 0) {
            return 0;
        }
        if (n == 1) {
            return 1;
        }
        if (memo.get(n) == -1) {
            memo.set(n,fib(n - 1) + fib(n - 2));
        }
        return memo.get(n);
    }

    public static void main(String[] args) {
        num = 0;
        int n = 42;
        for (int i = 0;i <= n;i++) {
            memo.add(-1);
        }
        long start = System.nanoTime();
        int res = Fibonacci.fib(n);
        long end = System.nanoTime();
        System.out.println(res);
        System.out.println((end - start) / 1000000000.0);
        System.out.println(num);
    }
}

此次咱們再來計算n = 42,運行結果

267914296
4.2859E-5
83

由結果可知,當咱們減小了計算次數,斐波那契算法的時間複雜度從O(2^n)一會兒降到了O(n)級別,這就至關於咱們在列表中命中了緩存,無需866988873次計算,而計算次數只下降到了83次。

相關文章
相關標籤/搜索