二叉树的最大深度
在做二叉树题的时候如果需要遍历,一定要想清楚用那种顺序的遍历。
递归版本:为了求深度,我们应该是知道了孩子节点的深度后返回给根节点然后求得到根节点的深度。所以这明显使用后序遍历。
本题也可以使用前序遍历,但是麻烦很多。
由此得到代码
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) return 0;
int left = maxDepth(root.left); //左
int right = maxDepth(root.right); //右
return Math.max(left,right)+1; //中
}
}
**迭代版本:**这道题除了后序遍历,层序遍历也是一个非常直观地办法,最大层数就是最大深度。
class Solution {
public int maxDepth(TreeNode root) {
Deque<TreeNode> queue = new LinkedList<>();
if(root != null) queue.add(root);
int depth = 0;
while(!queue.isEmpty()){
int count = queue.size(); //该层需要出队的元素数量
while(count -- >0){
TreeNode temp = queue.poll();
if(temp.left != null) queue.add(temp.left);
if(temp.right != null) queue.add(temp.right);
}
depth++;
}
return depth;
}
}
使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。
二叉树的最小深度
这题要注意读题:
题目中说的是:最小深度是从根节点到最近叶子节点的最短路径上的节点数量。注意是叶子节点。
所以,如果左子树为空,右子树不为空,说明最小深度是 1 + 右子树的深度。
反之,右子树为空,左子树不为空,最小深度是 1 + 左子树的深度。 最后如果左右子树都不为空,返回左右子树深度最小值 + 1 。
**递归版本:**后序遍历
lass Solution {
/**
* 递归法,相比求MaxDepth要复杂点
* 因为最小深度是从根节点到最近**叶子节点**的最短路径上的节点数量
*/
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if (root.left == null) {
return rightDepth + 1;
}
if (root.right == null) {
return leftDepth + 1;
}
// 左右结点都不为null
return Math.min(leftDepth, rightDepth) + 1;
}
}
迭代版本:和最大深度一样,使用层序遍历即可,只不过这时候好加入一个判断条件来处理最小深度的情况
class Solution {
public int minDepth(TreeNode root) {
Deque<TreeNode> queue = new LinkedList<>();
if(root != null) queue.add(root);
int depth = 0;
while(!queue.isEmpty()){
int count = queue.size(); //该层需要出队的元素数量
while(count -- >0){
TreeNode temp = queue.poll();
if(temp.left != null) queue.add(temp.left);
if(temp.right != null) queue.add(temp.right);
if(temp.left ==null && temp.right == null) return ++depth;
}
depth++;
}
return depth;
}
}
完全二叉树的节点个数
**递归版本:**这题采用前序遍历和后序遍历都可以,但是后序遍历的代码更为简单。
class Solution {
public int countNodes(TreeNode root) {
if(root == null ) return 0;
int left = countNodes(root.left); //左子树节点个数
int right = countNodes(root.right); //右子树节点个数
return left + right +1; //根节点处理
}
}
迭代版本:使用层序遍历当然也能够求得节点个数
Deque<TreeNode> queue = new LinkedList<>();
int count = 0;
if(root != null) queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
count += size;
while(size-->0){
TreeNode temp = queue.poll();
if(temp.left != null) queue.add(temp.left);
if(temp.right != null) queue.add(temp.right);
}
}
return count;
上面的两种写法其实换成普通二叉树依旧可以求得节点的数量。
在本题中既然给出了完全二叉树的概念,那么我们利用完全二叉树的性质还可以做到更快的时间复杂度来求得节点个数。
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
可以看出如果整个树不是满二叉树,就递归其左右孩子,直到遇到满二叉树为止,用公式计算这个子树(满二叉树)的节点数量。
这里关键在于如何去判断一个左子树或者右子树是不是满二叉树呢?
在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。
class Solution {
/**
* 针对完全二叉树的解法
*
* 满二叉树的结点数为:2^depth - 1
*/
public int countNodes(TreeNode root) {
if (root == null) return 0;
TreeNode left = root.left;
TreeNode right = root.right;
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
while (left != null) { // 求左子树深度
left = left.left;
leftDepth++;
}
while (right != null) { // 求右子树深度
right = right.right;
rightDepth++;
}
if (leftDepth == rightDepth) {
return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
}
return countNodes(root.left) + countNodes(root.right) + 1;
}
}