遞迴就是將大問題劃分為若干個子問題,各個問題是巢狀關係,最小的那個問題的結果是已知的,大問題不斷分解直到達到最小問題的過程叫做「遞」,小問題的解釋已知的,然後根據這個解回過去求大問題的解的過程叫做「歸」。最簡單的遞迴的例子就是求n的階乘:
其遞推公式為:f(n) = n * f(n-1),其中,f(1) = 1
遞迴需要滿足三個條件
乙個問題的解可以分解為幾個子問題
這個問題與分解之後的子問題,除了資料規模不同,求解思路完全一樣
存在遞迴終止條件
編寫遞迴**
找到規律
寫出遞推公式
找到終止條件
用簡單的例子驗證
比如這個問題:假如這裡有n個台階,每次你可以跨1個台階或者2個台階,請問走這n個台階有多少種走法?如果有7個台階,你可以2,2,2,1這樣子上去,也可以1,2,1,1,2這樣子上去,總之走法有很多,那如何用程式設計求得總共有多少種走法呢?
找到規律
這個問題可以根據第一步的走法把所有走法分為兩類,第一類是第一步走了1個台階,另一類是第一步走了2個台階。所以n個台階的走法就等於先走1階後,n-1個台階的走法 加上先走2階後,n-2個台階的走法。
寫出遞推公式
用公式表示就是:
f
(n)=
f(n-1)
+f(n-2
)
找到終止條件當n為1的時候,就只有一種走法,即f(1)=1
用簡單的例子驗證
假設n=2,根據遞推公式f(2) = f(1) + f(0),其實f(0)並不合理,因此重新思考下終止條件,應該是:
f(1
)=1;
f(2)
=3
**實現1:
class
solution
}
編寫遞迴**容易遇到的問題及解決辦法
1.堆疊溢位
函式呼叫會使用棧來儲存臨時變數等資訊,每呼叫乙個函式,就會將臨時變數封裝為棧幀壓入棧頂,等函式執行完成返回時,將該次函式呼叫所用的資訊從棧頂彈出。系統棧或者虛擬機器棧空間一般都不大。如果遞迴求解的資料規模很大,呼叫層次很深,一直壓入棧,就會有堆疊溢位的風險。
解決方案:
可以通過在**中限制遞迴呼叫的最大深度的方式來解決這個問題。遞迴呼叫超過一定深度(比如1000)之後,我們就不繼續往下再遞迴了,直接返回報錯。在遞迴的時候可以用乙個靜態變數用作遞迴深度的計數器。
2.重複計算問題
遞迴會出現重複計算的問題,比如台階問題,f(5)=f(4)+f(3),f(3)會被計算一次,當f(4)分解為f(3)+f(2)的時候,f(3)又會被計算一次。
解決方案:
可以用乙個資料結構將已經計算的結果儲存起立,當再次使用到該結果的時候就可以直接返回。以台階問題舉例:
**實現2:
class
solution
$ret
=$this
->
climbstairs($n
-1)+
$this
->
climbstairs($n
-2);
$this
->
result[$n
]=$ret
;return
$ret;}
}
3.時間效率和空間效率
遞迴的呼叫深度很深的時候,會積聚乙個較大的時間成本和空間成本。
將遞迴**改寫為非遞迴**
遞迴有利有弊,利是遞迴**的表達力很強,寫起來非常簡潔;而弊就是空間複雜度高、有堆疊溢位的風險、存在重複計算、過多的函式呼叫會耗時較多等問題。所以,在開發過程中,我們要根據實際情況來選擇是否需要用遞迴的方式來實現。
**實現3:
class
solution
return
$ret;}
}
台階問題三種解法的比較
test1.php是未經優化的遞迴解法
test2.php是優化過的遞迴解法
test3.php是非遞迴解法
遞迴之台階問題
乙隻青蛙一次可以跳上1級台階,也可以跳上2級。求該青蛙跳上乙個n級的台階總共有多少種跳法。當n 1時,次數f n 1。當n 2時,次數f n 2。11或2 當n 2時,當前一步可以跳一級,也可以跳兩級,次數f n f n 1 f n 2 public int jumpfloor int number...
爬台階 遞迴
先說一下遞迴的作用 1.替代多重迴圈 2.解決本來就是遞迴形式定義的問題 3.將問題分解為規模更小的子問題進行求解 這裡是將問題分解為規模更小的子問題進行求解 先考慮第一步怎麼做,根據第一步把問題分為幾大類,剩下的事情就變成乙個子問題,這個子問題可能是形式相同但規模更小,就可以寫出遞推式,再寫出邊界...
跳台階問題 遞迴演算法
首先我們說說什麼是遞迴。程式呼叫自身的程式設計技巧稱為遞迴 recursion 遞迴做為一種演算法在 程式語言 中廣泛應用。乙個過程或 函式在其定義或說明中有直接或間接呼叫自身的一種方法,它通常把乙個大型複雜的問題層層轉化為乙個與原問題相似的規模較小的問題來求解,遞迴策略只需少量的程式就可描述出解題...