求一棵二叉树的最小深度
问题描述: 给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
普通解法:二叉树的递归套路
时间复杂度O(n),需要遍历所有的节点。
空间复杂度为O(h)。其中,h 表示二叉树的高度,也就是递归使用的系统调用栈的高度。
记头节点为 root
- 左子树为空,求右子树的最小高度 + 1
- 右子树为空,求左子树的最小高度 + 1
- 左、右子树不为空,求左子树的最小高度 + 1,求右子树的最小高度 + 1
- 左、右子树都为空,最小高度为 1
class Solution {
public int minDepth(TreeNode root) {
if (root != null) {
if (root.left == null || root.right == null) {
// 只有一个孩子或没有孩子
return Math.max(minDepth(root.left), minDepth(root.right)) + 1;
} else {
// 有两个孩子
return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
}
} else return 0;
}
}
进阶:Morris遍历改写
时间复杂度O(n),需要遍历所有的节点。
空间复杂度为O(1)。
思路:
首先,解决在morris遍历中得到每一个当前节点的深度。
遍历的当前节点记为 cur,cur的深度是 level
morris遍历中,下一个节点深度是多少?
morris遍历的规则:
-
如果cur没有左子树,cur向右移动(cur = cur.right),那么下一个节点就是cur的右孩子,深度:level+1。
-
如果cur有左子树,找到cur左子树上最右的节点,记mostRight。
①如果 mostRight 的 right 指针指向null,让其指向cur(mostRight.right = cur),cur向左移动(cur =.cur.left),那么下一个节点就是cur的左孩子,深度:level+1。
②如果 mostRight 的right 指针指向 cur,让其指向空( mostRight.right = null),cur向右移动(cur= cur.right)假设下一个节点记为next,根据 morris遍历可知,cur是next左子树上最右的节点。next 的深度 = level - next左子树的右边界的节点数。
利用以上策略,就能在morris遍历中得到每一个节点的深度。
其次,解决如何在morris遍历中发现每一个叶节点
因为在morris遍历中,我们会人为修改某些节点的 right 指针,让其指向上级的某个节点。这样,当用morris遍历到某个节点×的时候,也许×原本是叶节点,但此时却发现不了,因为此时X的 right 指针指向上级了(不满足X.left == null && X.right = null)。
所以,为了发现所有的叶节点,我们把发现叶节点的时机放在morris遍历中回到自己两次,且第二次回到这个节点的时候。
比如,使用Mirror遍历二叉树时(上图所示):
当第二次回到2的时候,看看1是不是叶节点;
当第二次回到4的时候,看看3是不是叶节点;
当第二次回到6的时候,看看5是不是叶节点;
最后单独看一下整棵树的最右节点是不是叶节点。
这样就能在morris遍历中找到所有的叶节点了。做到了在morris遍历中,每一个节点的深度都能得到;也做到了在morris遍历中发现所有的叶节点。这个问题自然可以求解,遍历的代价就是morris 遍历的代价,时间复杂度为O(N),额外空间复杂度O(1)。
// 根据 morris 遍历改写
public static int minHeight