LeetCode 110. 平衡二叉树
题目描述


题意分析
判断整棵二叉树是否满足高度平衡:对于每一个节点,它的左右子树高度差都不能超过
1。这里比较的是子树高度,不是左右两边的节点数量。条件要求对所有节点成立。即使根节点两边等高,某棵子树内部也可能已经失衡,因此不能只比较根节点;空树满足平衡条件。
解法:后序 DFS 返回高度或失衡标记
核心思路
[!blue]
判断一个节点是否平衡,需要先知道左右子树的高度,还要知道这两棵子树内部是否平衡。因此适合后序遍历:先处理孩子,再根据它们返回的信息判断当前节点。
用一个整数同时携带两种信息:非负数表示“这棵子树平衡,数值是它的高度”,
-1表示“这棵子树中已经存在失衡节点”。空子树返回0,所以-1不会与任何正常高度冲突。先递归左子树。如果它返回
-1,当前子树无论右边怎样都不可能满足“所有节点平衡”,可以立即返回-1。右子树同理。只有两边都平衡,才比较它们的高度差;超过1就在当前节点判定失衡,否则返回max(leftHeight, rightHeight) + 1。这样每个节点在求高度时顺便完成平衡检查,父节点直接复用结果,不必为了检查每个节点而反复遍历其后代。失衡标记会一直传到根,主函数只需判断根的返回值是否为
-1。
解题步骤
- 当前节点为空时返回
0,表示空子树的高度。- 递归求左子树结果。如果为
-1,立即返回失衡标记。- 递归求右子树结果,同样先检查是否已经失衡。
- 两边都给出正常高度后,若高度差的绝对值大于
1,返回-1;否则返回较大高度加1。- 主函数检查整个树的结果,不等于
-1就返回true。
代码实现
class Solution {
public boolean isBalanced(TreeNode root) {
return height(root) != -1;
}
private int height(TreeNode node) {
if (node == null) {
return 0;
}
int leftHeight = height(node.left);
// 失衡标记直接向上传递,不能再当作正常高度。
if (leftHeight == -1) {
return -1;
}
int rightHeight = height(node.right);
if (rightHeight == -1) {
return -1;
}
// 两侧各自平衡后,还要检查当前节点的高度差。
if (Math.abs(leftHeight - rightHeight) > 1) {
return -1;
}
return Math.max(leftHeight, rightHeight) + 1;
}
}
func isBalanced(root *TreeNode) bool {
return heightOrUnbalanced(root) != -1
}
func heightOrUnbalanced(node *TreeNode) int {
if node == nil {
return 0
}
leftHeight := heightOrUnbalanced(node.Left)
// 失衡标记直接向上传递,不能再当作正常高度。
if leftHeight == -1 {
return -1
}
rightHeight := heightOrUnbalanced(node.Right)
if rightHeight == -1 {
return -1
}
// 两侧各自平衡后,还要检查当前节点的高度差。
if absInt(leftHeight-rightHeight) > 1 {
return -1
}
return maxInt(leftHeight, rightHeight) + 1
}
func absInt(num int) int {
if num < 0 {
return -num
}
return num
}
func maxInt(a int, b int) int {
if a > b {
return a
}
return b
}
复杂度分析
- 时间复杂度:$O(n)$。每个节点至多访问一次,高度由两个子结果直接合成。
- 空间复杂度:$O(h)$。
h为树高,递归栈在平衡树上为 $O(\log n)$,链状树最坏为 $O(n)$。
关键点总结
[!green]
- 当前节点的判断同时依赖孩子的高度和孩子是否平衡,不能丢掉任一信息。
- 后序返回高度,使整棵树只需遍历一次,不重复计算子树高度。
-1是失衡信号,收到后直接向上传递,不能参与正常高度的合并。
易错点总结
[!yellow]
- 只比较根节点两侧高度,会遗漏子树内部已经发生的失衡。
- 用左右节点数之差代替高度差,检查的不是题目要求的条件。
- 高度差恰好为
1仍然平衡,判定条件应为> 1,而不是>= 1。- 只检查
leftHeight - rightHeight > 1会漏掉右边更高的情况,需要取绝对值。- 空节点应返回
0;返回-1会错误地把空子树判为失衡。- 收到
-1后仍做max + 1,可能把失衡标记转换成非负高度,丢失错误信息。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 104. 二叉树的最大深度 | 简单 | 后序求高度是基础,本题同时把子树是否失衡的信息向上传递。 |
| 543. 二叉树的直径 | 简单 | 同样用左右子树高度在当前节点计算附加结果,原题求最长路径长度。 |
| 124. 二叉树中的最大路径和 | 困难 | 后序返回子树高度并在根处合并信息;本题额外验证两侧高度差,该题舍弃负贡献后合并最大路径和。 |
| 687. 最长同值路径 | 中等 | 后序返回子树高度并在根处合并信息;本题额外验证两侧高度差,该题仅连接值相同的向下链。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!