Dynamic Programming

What is dynamic programming

  • The technique of storing repeated computations in memory
  • Use more space to take less time

可以用dynamic programming 解決的問題具備的兩大性質

1. optimal substructure

例如,可以表達為f(n) = f(n-1) + f(n-2)
A useful way to think about optimal substructure is whether a problem can be easily solved recursively. Recursive solutions inherently solve a problem by breaking it down into smaller subproblems. If you can solve a problem recursively, it most likely has an optimal substructure.
能用recession方法解決的問題一般可以用這種方法解決。

2. overlapping subproblems

Dynamic programming relies on overlapping subproblems, because it uses memory to save the values that have already been computed to avoid computing them again. The more overlap there is, the more computational time is saved.
重復計算,比如fib(5) = fib(4) + fib(3), 在計算fib (5) & fib(4)都需要計算fib(3)

解決一道interview問題的方法-- FAST

  • First solution
  • Analyze the first solution
  • Identify the Subproblems
  • Turn the solution around

下面以經典的計算Fibonacci numbers為例說明這個方法的使用

  • First solution
    寫出最直觀的解法,在這里是recursion
public int fib(int N) {
        if(N <= 1) {
            return N;
        }
        return fib(N-1) + fib(N-2);
    }
  • Analyze the first solution
    通過分析上面的解法我們可以發(fā)現,這個計算過程可以總結為一個式子fib(n) = fib(n-1) + fib(n-2)
    而在我們的recursion解法中,從上往下計算,會使得許多東西被重復計算,如fib(3)在計算fib(4)fib(5)的時候都需要被計算。因此,如果將已經計算過的值儲存起來,就可以不需要重復計算了
  • Identify the Subproblems
    按照前面的分析,把計算過的值儲存在cache中,就減少了一部分計算量
public int fib(int N) {
        if(N < 2) {
            return N;
        } 
        int[] cache = new int[N+1];
        Arrays.fill(cache, -1);
        cache[0] = 0;
        cache[1] = 1;
        return fib(N, cache);
    }
    public int fib(int n, int[] cache) {
        if(cache[n] >= 0) {
            return cache[n];
        }
        cache[n] = fib(n-1, cache) + fib(n-2, cache);
        return cache[n];
    }
  • Turn the solution around
    上面的解法還是一個從上到下的計算過程,現在我們要把這個過程倒過來,變成從下到上
public int fib(int N) {
        if(N < 2) {
            return N;
        } 
        int[] cache = new int[N+1];
        cache[1] = 1;
        for(int i = 2; i <= N; i++) {
            cache[i] = cache[i-1]+cache[i-2];
        }
        return cache[N];
    }

接著,我們對這個解法進行進一步的優(yōu)化,我們注意到計算fib(n)的時候只需要它的前兩個值,所以每次只要儲存前兩個值就好了,不需要從1到n都存。可以作如下優(yōu)化

public int fib(int N) {
        if(N < 2) {
            return N;
        } 
        int n1 = 0, n2 = 1;
        for(int i = 2; i <= N; i++) {
            int n = n1 + n2;
            n1 = n2;
            n2 = n;
        }
        return n2;
    }
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容