最近在一些大牛那學了樹相關的遞歸算法,記錄一下。以便以後回顧。
1、何爲遞歸
遞歸就是循環定義,對於一個方法來說,就是自己調用自己。當一個問題的解決方案是重複的執行某個步驟,直到問題得到解決時。這時候你就想想,是不是該用遞歸去解決了。它能用幾行簡單的代碼去解決複雜的問題。
2、遞歸要點
當你選擇使用遞歸時,就必須考慮到以下幾個點,也是你寫代碼時必須遵循的要點(後續代碼會按照以下步驟去解決):
1、遞歸的終止條件。這是寫遞歸的必要條件,如果沒有終止條件,遞歸就無法結束,也就沒有意義去使用遞歸。
2、循環重複處理得邏輯。這也是你使用遞歸首先要考慮得,該問題是否是通過循環處理就可以得到解決。若是可以,它每次重複處理得內容是什麼。
3、返回值。每次遞歸需要返回一個值給上層或下層。給上下層使用。需要考慮他們需要得返回值是什麼。
那麼如何得出這三要點呢。舉例說明。比如,讓你計算1到100的和。採用遞歸方法代碼:
public class test {
public static int add(int num,int i) {
//終止條件
if(i > 100) {
return num;
}
//本層邏輯內容
num = num + i;
i = i + 1;
//返回值
return add(num,i);
}
public static void main(String args[]) {
int sum= add(0,1);
System.out.println(sum);
}
}
首先,考慮第一個要點,什麼時候終止,1加到100。肯定到i >100得時候。就不需要繼續了,100爲終止條件。第二個要點。循環得處理邏輯是什麼。每一層需要幹什麼。需要將以前的值都加上.i是從1到100得。i逐層加1 .所以需要num=num+1;i = i+1;第三個要點,下層需要什麼。需要這一層得和。告訴下一層,我已經加到第4層了(1+2+3+4)。以此類推。
可能問題過於簡單,還體會不到遞歸得方便,也不好體現這三要點。下面通過樹與圖得相關總結來體現。
3、遞歸運用–樹相關算法。
1、樹得前序,中序,後序,深層遍歷
這是摘自leetcode上面的一道算法題-翻轉二叉樹。
這道題可以用來作爲遞歸和樹的排序的經典例題。借鑑了一些大佬的解題思路,所以想詳細分析一下。
首先分析一下這道題,翻轉二叉樹做的是什麼。將每個節點的左右子節點交換。有終止條件嗎?有,當子節點都爲空時結束。有循環重複處理的的嗎?有,交換左右子節點。返回值需要返回給上下層嗎?需要,每個節點的既可以是父節點,也可以是子節點,必然需要返回給上下層進行繼續交換。既然三個條件都滿足,那好,我們用遞歸開始解題。
不明白前序,中序,後序遍歷是啥樣的,自行百度一下。
1、前序遍歷。
代碼如下:
//終止條件
if(root == null){
return null;
}
//處理邏輯--前序遍歷,從上往下,交換左右
TreeNode rightNode = root.right;
root.right = invertTree(root.left);
root.left= invertTree(rightNode );
//返回值
return root;
是不是看起來很簡單。但是寫的時候感覺無從下手。那麼回頭文章開始,三部曲。
第一步終止條件。節點爲空,直接返回,不處理,沒問題。
第二步處理邏輯。這部分比較重要。因爲遞歸歸根結底就是循環的做相同的事。那麼我只關注我這一層循環是幹了什麼就行。那麼對於任意一層,我們可以看作。父節點。左子節點,右子節點。需要做的就是,交換左右子節點。首先,保存左子節點。然後,令當前左子節點等於已經翻轉完的右子節點。接着,當前右子節點等於將剛剛保存的左子節點進行翻轉完的節點。也就是從上往下交換(前序遍歷)。
第三步返回值。就不用說了。返回當前節點。
2、中序遍歷。(只放代碼與註釋)
public TreeNode invertTree(TreeNode root) {
//終止條件
if(root == null){
return null;
}
//處理邏輯
TreeNode leftNode = invertTree(root.left);//遞歸找到最左節點
root.left = root.right;//處理父節點的左右交換
root.right = leftNode;
invertTree(root.left);//處理右節點,注意此時的右節點已經賦值給左節點了。
//返回值
return root;
}
3、後序遍歷 (只放代碼與註釋)
public TreeNode invertTree(TreeNode root) {
//終止條件
if(root == null){
return null;
}
//處理邏輯--後序遍歷從下往上。先解決左右,在往上遞歸
TreeNode leftNode = invertTree(root.left);//遞歸找到左節點並保存
root.left = invertTree(root.right);//將右節點賦值給左節點
root.right = leftNode;//左節點賦值給右節點
//返回值
return root;
}