遞歸能夠很方便的解決不少問題,讓程序變得很簡潔。java
可是,在遞歸解決問題的過程成,有時候會有不少重複計算,使得計算量很大,耗時很長。數組
好比,使用遞歸求斐波那契數列。ide
若是用普通的遞歸來解,當n值很大時,時間會很長而超時。學習
如圖,當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
再看一下斐波那契數列的運行時圖:
能夠看到,有大量的重複計算。
有沒有什麼辦法能夠優化呢?
若是咱們能記錄一些狀態的中間結果,在須要的時候直接讀取結果,就能夠減小重複計算。
這個思想叫着記憶化。
對於斐波那契數列,咱們能夠把計算完 n=2,n=3時...的值保存在數組中,下次須要使用他們來計算其餘n值時,從數組中取出來,而不去再計算。
按照這個思想,代碼修改成:
能夠看到,通過記憶化優化後的程序,運行速度快了不少。
下面咱們再看個例子。
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敲門磚(驗證信息):高山流水