題目描述(簡單難度)
返回從根節點到葉子節點最小深度。
解法一 遞歸
和 104 題 有些像,當時是返回根節點到葉子節點的最大深度。記得當時的代碼很簡單。
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
這道題是不是隻要把Math.max,改成Math.min就夠了。
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
}
粗略的想一下,似乎很完美,比如題目給的例子
3
/ \
9 20
/ \
15 7
根據代碼走一遍,root.left返回 1,root.right返回 2,選較小的1,加上 1 返回結果2,完美符合結果。
但如果是下邊的樣子呢?
3
/ \
9 20
/ / \
8 15 7
區別在於有一個子樹的擁有一個孩子,另一個孩子爲空。
這樣利用上邊的算法,當考慮9這個子樹的時候,左孩子會返回1,由於它的右孩子爲null,右孩子會返回0,選較小的0,加上 1 返回結果1給上一層。
也就是最頂層的root.left依舊得到了 1,但明顯是不對的,對於左子樹,應該是從 9 到 8,深度應該是 2。
所以代碼上需要修正這個算法,再想想題目要求是從根節點到葉節點,所以如果有一個子樹的左孩子或者右孩子爲null了,那就意味着這個方向不可能到達葉子節點了,所以就不要再用Min函數去判斷了。
我對代碼的修正如下:
class TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){val=x;}
}
public class Minimum_Depth_of_Binary_Tree {
public static int minDepth(TreeNode root) {
if(root==null) return 0;
return minDepthHelper(root);
}
private static int minDepthHelper(TreeNode root) {
if(root.left==null && root.right==null) return 1;
//左孩子爲空,只考慮右孩子的方向
if(root.left==null) return minDepthHelper(root.right)+1;
//右孩子爲空,只考慮左孩子的方向
if(root.right==null) return minDepthHelper(root.left)+1;
return Math.min(minDepthHelper(root.left), minDepthHelper(root.right))+1;
}
public static void main(String args[]) {
TreeNode[] node=new TreeNode[6];
node[0]=new TreeNode(3);
node[1]=new TreeNode(9);
node[2]=new TreeNode(20);
node[3]=new TreeNode(8);
node[4]=new TreeNode(15);
node[5]=new TreeNode(7);
node[0].left=node[1];
node[0].right=node[2];
node[1].left=node[3];
node[2].left=node[4];
node[2].right=node[5];
int ans=minDepth(node[0]);
System.out.println(ans);
}
}
其實也是可以把兩個函數合在一起的,參考這裏。
public int minDepth(TreeNode root) {
if (root == null){
return 0;
}
// 左孩子爲空,只考慮右孩子的方向
if (root.left == null) {
return minDepth(root.right) + 1;
}
// 右孩子爲空,只考慮左孩子的方向
if (root.right == null) {
return minDepth(root.left) + 1;
}
return Math.min(minDepth(root.left),minDepth(root.right)) + 1;
}
此外,還有一個想法,覺得不錯,大家可以看看,參考這裏。
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left != null && root.right != null) {
return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
} else {
return Math.max(minDepth(root.left), minDepth(root.right)) + 1;
}
}
當左孩子爲空或者右孩子爲空的時候,它就直接去選一個較大深度的,因爲較小深度一定是爲空的那個孩子,是我們不考慮的。
上邊三個算法本質上其實是一樣的,就是解決了一個孩子爲空另一個不爲空的問題,而對於104 題 沒有出現這個問題,是因爲我們選的是max,所以不用在意是否有一個爲空。
解法二 BFS
104 題 也提供了BFS的方案,利用一個隊列進行層次遍歷,用一個 level 變量保存當前的深度,代碼如下:
public int maxDepth(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<TreeNode>();
List<List<Integer>> ans = new LinkedList<List<Integer>>();
if (root == null)
return 0;
queue.offer(root);
int level = 0;
while (!queue.isEmpty()) {
int levelNum = queue.size(); // 當前層元素的個數
for (int i = 0; i < levelNum; i++) {
TreeNode curNode = queue.poll();
if (curNode != null) {
if (curNode.left != null) {
queue.offer(curNode.left);
}
if (curNode.right != null) {
queue.offer(curNode.right);
}
}
}
level++;
}
return level;
}
對於這道題就比較容易修改了,只要在 for 循環中判斷當前是不是葉子節點,如果是的話,返回當前的 level 就可以了。此外要把level初始化改爲1,因爲如果只有一個根節點,它就是葉子節點,而在代碼中,level 是在 for循環以後才++的,如果被提前結束的話,此時應該返回1。
public int minDepth(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<TreeNode>();
List<List<Integer>> ans = new LinkedList<List<Integer>>();
if (root == null)
return 0;
queue.offer(root);
/**********修改的地方*****************/
int level = 1;
/***********************************/
while (!queue.isEmpty()) {
int levelNum = queue.size(); // 當前層元素的個數
for (int i = 0; i < levelNum; i++) {
TreeNode curNode = queue.poll();
if (curNode != null) {
/**********修改的地方*****************/
if (curNode.left == null && curNode.right == null) {
return level;
}
/***********************************/
if (curNode.left != null) {
queue.offer(curNode.left);
}
if (curNode.right != null) {
queue.offer(curNode.right);
}
}
}
level++;
}
return level;
}