遞歸原來能夠so easy|-連載(4)

對遞歸進行優化--記憶化

遞歸能夠很方便的解決不少問題,讓程序變得很簡潔。java

可是,在遞歸解決問題的過程成,有時候會有不少重複計算,使得計算量很大,耗時很長。數組

好比,使用遞歸求斐波那契數列。ide

若是用普通的遞歸來解,當n值很大時,時間會很長而超時。學習

遞歸原來能夠so easy|-連載(4)

如圖,當n等於45時,須要運行5秒才能求出結果。優化

分析一下,會是什麼緣由致使須要計算這麼長時間呢?code

根據斐波那契數列的遞推公式:blog

fn=f(n-1)+f(n-2)遞歸

f(n-1)=f(n-2)+f(n-3)
f(n-2)=f(n-3)+f(n-4);
以上3行合併一下:
fn=( f(n-2)+f(n-3) ) + ( f(n-3)+f(n-4) )源碼

能夠看到, f(n-3)被重複計算了。it

再看一下斐波那契數列的運行時圖:
遞歸原來能夠so easy|-連載(4)

能夠看到,有大量的重複計算。

有沒有什麼辦法能夠優化呢?

若是咱們能記錄一些狀態的中間結果,在須要的時候直接讀取結果,就能夠減小重複計算。

這個思想叫着記憶化。

對於斐波那契數列,咱們能夠把計算完 n=2,n=3時...的值保存在數組中,下次須要使用他們來計算其餘n值時,從數組中取出來,而不去再計算。

按照這個思想,代碼修改成:
遞歸原來能夠so easy|-連載(4)

能夠看到,通過記憶化優化後的程序,運行速度快了不少。

下面咱們再看個例子。

數字三角形問題

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
如上圖所示,第一行有一個數字5,表示數字三角形共有5層。

後面5行爲各層的數字,組成一個數字三角形。

給出一個三角形,從三角形的頂點,只能走左下方或者右下方,而後把所遍歷的數字加起來,求出最大的值。
好比對於上圖來講,答案就是30(7+3+8+7+5)。

現給定一個任意的數字三角形,輸出最大的值。

咱們從頂點(也就是第一行第一列)開始走,其最大值爲頂點的值加上從他下面兩個數開始,走到底邊的最大值中,更大的那個,由此,咱們把問題分解成求第一行的數字到底邊的最大值,到求第二行的數字到底邊的最大值,這就造成了遞歸。
而遞歸的終止條件是到了最後一行,其值就是它自己。
遞歸的代碼以下:

package test;

import java.util.Scanner;

public class Hello {
    static int d[][] = new int[100][100]; // 最多100層
    static int n;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt(); // 總共有幾層
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= i; j++)
                d[i][j] = sc.nextInt();
        int m = MaxSum(1, 1);
        System.out.println("最大值:"+m);
    }

    static int MaxSum(int l, int r) {
        if (l == n)
            return d[l][r];
        else
            return Math.max(MaxSum(l + 1, r), MaxSum(l + 1, r + 1)) + d[l][r];
    }

}

樣例輸入輸出:

輸入:

6
2
96 30
83 52 60
21 65 44 61
8 79 50 41 21
61 41 50 38 79 10

輸出
375

若是經過記憶化進行優化呢?

思考一下........

....................................................................................................................

public class Hello {
    static int d[][] = new int[100][100]; // 最多100層
    static int max[][]= new int[100][100]; //保存記憶
    static int n;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt(); // 總共有幾層
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= i; j++)
                d[i][j] = sc.nextInt();
        int m = MaxSum(1, 1);
        System.out.println("最大值:"+m);
    }

    static int MaxSum(int l, int r) {
        if (l == n)
            return d[l][r];
        else {
            if(max[l][r]!=0) {
                return max[l][r];
            }else {
                int x=Math.max(MaxSum(l + 1, r), MaxSum(l + 1, r + 1)) + d[l][r];
                max[l][r]=x;
                return x;               
            }
        }
    }
}

源碼、更多資深講師相關課程資料、學習筆記請入羣后向管理員免費獲取,更有專業知識答疑解惑。入羣即送價值499元在線課程一份。

QQ羣號:560819979敲門磚(驗證信息):高山流水

相關文章
相關標籤/搜索