目錄前言
1、求二叉樹的最大深度 leetcode104
2、求二叉樹的最小深度 leetcode111
3、求二叉樹的正向/逆向數字路徑和 leetcode129
4、求二叉樹的節點路徑和 leetcode437
5、小結(重要)
二叉樹的路徑搜尋就是乙個簡易版的行程回溯演算法,之所以是簡易版是因為行程路徑最多僅有兩條。因此,如果只要搜尋一條滿足條件的路徑,搜尋到即可停止,參見 leetcode 112. 路徑總和。如果需要搜尋多條滿足條件的路徑,搜尋本節點時需要修改行程,搜尋完畢後需要恢復原來的行程,參見 leetcode 113.
路徑總和 ii 。
public static int countmaxdeepth(treenode root)
return math.max(countmaxdeepth(root.left),countmaxdeepth(root.right)) + 1;
}
dfs、bfs都行。
本題的核心在於:二叉樹的最小深度含義是距離根節點最近的葉節點層數
1、葉子節點的定義是左孩子和右孩子都為 null 時叫做葉子節點
2、當 root 節點左右孩子都為空時,返回 1
3、當 root 節點左右孩子有乙個為空時,返回不為空的孩子節點的深度,而不是本節點 + 1 //最易出錯的點
4、當 root 節點左右孩子都不為空時,返回左右孩子較小深度的節點值
記住以下這個簡單的例子,保證第 3 條不會出錯:
1\2
\3
遞迴**實現如下:
public static int countmindepth(treenode root)
int min = 0;
if(root.left == null && root.right == null)else if(root.left == null)else if(root.right == null)else
return min + 1;
}
上面的**的時間複雜度恒為o(n),也就是說需要遍歷樹中的所有節點,假設我們找到了乙個距離根節點的葉節點,更新當前的葉節點的層數 mindepth,後面當搜尋的層數 depths 大於 mindepth 時停止搜尋。
**實現:
public static int countmindepth(treenode root)
countmindepth(root,1);
return mindepth; }
private void mindepth = integer.max_value;
public void countmindepth(treenode root,int depth)
if(root.left == null && root.right == null)
countmindepth(root.left,depth+1);
countmindepth(root.right,depth+1);
}
也可以使用bfs法,搜尋到葉節點就停止。平衡二叉樹是本演算法的最壞情況。
public int sumnumbers(treenode root)
//正序根節點是高位,葉節點是低位
public int sumnumbers(treenode root,int cursum)
int sum = cursum*10 + root.val;
if(root.left == null && root.right == null)
return sumnumbers(root.left,sum) + sumnumbers(root.right,sum); }
//逆序根節點是低位,葉節點是高位
public int sumnumbers(treenode root,int cursum,int decimal)
int sum = cursum + decimal*root.val;
if(root.left == null && root.right == null)
return sumnumbers(root.left,sum,decimal*10) + sumnumbers(root.right,sum,decimal*10);
}
逆序求和:葉節點是高位,根節點是低位,需要將樹的層數即數字的位數 傳遞到底層直至葉節點。
參見 leetcode 437. 路徑總和 iii,面試題 04.12. 求和路徑 。給定一棵二叉樹,其中每個節點都含有乙個整數數值(該值或正或負)。設計乙個演算法,列印節點數值總和等於某個給定值的所有路徑的數量。注意,路徑不一定非得從二叉樹的根節點或葉節點開始或結束,但是其方向必須向下(只能從父節點指向子節點方向)。示例:給定如下二叉樹,以及目標和sum = 22。
5
/ \4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
返回:3
解釋:和為 22 的路徑有:[5,4,11,2], [5,8,4,5], [4,11,7]
方法一:暴力破解
儲存 當前節點值 給下一層使用,第 n 層節點都知道(1,2,.. n-1)層節點到本層節點的路徑之和。複雜度o( n * levels)。
public int pathsum(treenode root, int sum)
private int hasviladpathcnt = 0;
public void pathsum(treenode root, listsumlist,int targetsum)
int listsize = sumlist.size();
for(int i = 0; i < listsize; i++)
sumlist.set(i,tmp);//更新目標和序列
}if(targetsum == root.val)
sumlist.add(targetsum - root.val); //本節點新增到目標和路徑中
pathsum(root.left, sumlist,targetsum);
pathsum(root.right, sumlist,targetsum);
sumlist.remove(listsize);//刪除本節點
for(int i = 0; i < listsize; i++)
}
方法二:暴力破解2,深度搜尋
對樹中的每個節點進行 dfs 路徑匹配,類似於leetcode1367. 二叉樹中的列表,具體說:以樹中的任一節點為起點向下搜尋所有路徑,查詢滿足條件的路徑。
public int dfspathsum(treenode root, int sum)
sum = sum - root.val;
int len = 0;
if(sum == 0)
return len + dfspathsum(root.left,sum) + dfspathsum(root.right,sum);
} public int pathsum(treenode root, int sum)
//本節點為起點進行深搜,本節點的左右子樹繼續深搜
return dfspathsum(root,sum) + pathsum(root.left,sum) + pathsum(root.right,sum);
}
1、路徑滿足條件即給定的目標和 targetsum 通常可以用逐次的減去當前節點的值 val,當減到0時即滿足路徑和的條件。這樣可以減少乙個引數 cursum(當前路徑之和)。
2、遞迴搜尋的過程中需要,注意空間節點 (root == null) 的處理,當該節點為空的返回值是什麼? false、true、0、等異常值需要重點考慮。
3、普通節點處理需要分為四種邏輯:
1)左、右子節點為空(葉節點),(root.left == null && root.right == null);
2)左子節點為空右子節點不為空(無左子樹),(root.left == null && root.right != null);
3)右子節點為空左子節點不為空(無右子樹),(root.left!= null && root.right == null);
4)左、右子節點不為空(普通節點),(root.left != null && root.right != null);
二叉樹的一些問題
二叉樹的先序遍歷 遞迴 void preorder btnode ptr 二叉樹中序遍歷 遞迴 void inorder btnode ptr 二叉樹後序遍歷 遞迴 void pastorder btnode ptr 先序遍歷二叉樹 非遞迴 void nicepastorder btnode ptr...
關於二叉樹的一些問題
tips 關於二叉樹的絕大多數問題都可以用遞迴方法來實現,dfs。一位二叉樹根節點去掉之後又分為兩個子樹,對於子樹本身也可以看左二叉樹來處理。所以遞迴可以說很好用了 二叉樹的建立 public class bittree public bittree int data public static b...
二叉樹路徑搜尋問題
1 求任意二叉樹中的所有路徑 細想一下,這其實是乙個dfs問題。有乙個helper函式,用來向list中新增string。這裡為什麼要用靜態的string而不是動態的stringbuilder?另乙個問題是,要動態地新增內容給list,從思路上講應該是回溯法。回溯用動態子結構比如list的話,就需要...