遞歸
- 電影院
- 求階乘
- 斐波那契數
- 數字反轉
- 求台階走法數
當然,很多遞歸都是可以優化的,比如f(n)=f(n-1)+f(n-2),這里f(n-2)就會計算兩次,可以用散列表存儲已經計算的數據,但是這里主要演示遞歸思想,不再進行優化。
電影院
周末你帶着女朋友去電影院,女朋友問你,咱們現在坐在第幾排啊,電影院太黑沒法數怎么辦,於是你問前一排的人他是第幾排,你只需要在他的數字上加一就知道自己是第幾排,但是前面的人也看不清啊。所以他也問前面的人,就這樣一排一排的問直到問到第一排的人
- 這是一個非常標准的遞歸求解問題的分解過程,去的過程叫遞,回來的過程叫歸。基本上,所有的遞歸問題都可以用遞推公式來表示。剛剛這個生活中的例子,我們用遞推公式將它表示出來是這樣的:
f(n) = f(n-1) +1 其中,f(1) = 1
- f(n)代表你想知道自己在哪一排,f(n-1)表示前面一排所在的排樹。核心代碼如下:
public static int cinemas(int n){
if (n == 1)
return 1;
return cinemas(n-1)+1;
}
求階乘
求階乘思路跟上面差不多,其遞推式為:
f(n) = f(n-1) * n
- 核心代碼如下:
public static int recursion(int n){
if (n == 1) return 1;
return recursion(n-1)*n;
}
斐波那契數
斐波那契數的排列是:0,1,1,2,3,5,8,13,21,34,55,89,144……。依次類推下去,你會發現,它后一個數等於前面兩個數之和,在這個數列中的數字,就被稱為斐波那契數
-
很容易得到斐波那契數的遞推式為:
f(n) = f(n-1) + f(n-2),其中f(0) = 0,f(1) = 1
-
核心代碼如下:
public static int recursion(int n){
if (n <= 1) return n;
return recursion(n-1) +recursion(n-2);
}
數字反轉
反轉數字
- 反轉一個數字,可以用遞歸方法,直接上代碼
public static void recursion(int n){
System.out.println(n % 10);
if (n >= 10){
recursion(n / 10);
}
}
求台階數
假設這里有n個台階,每次你可以跨1個台階或者兩個台階,請問走這n個台階有多少種走法。
-
每一次有兩種走法,結束的條件是n = 1的時候只有一種走法,n = 2的時候有兩種走法
,遞歸式如下:f(n) = f(n-1) + f(n-2)
-
核心代碼如下:
public static int recursion(int n){
if (n == 1) return 1;
if (n == 2) return 2;
return recursion(n-1)+recursion(n-2);
}
總結:
遞歸需要滿足三個條件
- 一個問題的解可以分為幾個子問題的解
- 這個問題與分解后的子問題,除了數據規模不同,求解方式相同
- 存在遞歸終止條件
遞歸代碼要警惕堆棧溢出
函數調用會使用棧來保存臨時變量。每調用一個函數,都會將臨時變量封裝為棧幀壓入內存棧,等函數執行完成返回時,才出棧。系統棧或者虛擬機棧空間一般都不大。如果遞歸求解的數據規模很大,調用層次很深,一直壓入棧,就會有堆棧溢出的風險。可以用一個變量設置做多遞歸多少次,超過一定次數自己拋出異常