【LeetCode 每日一题】110. 平衡二叉树——(解法二)自底向上 + 剪枝

Problem: 110. 平衡二叉树

文章目录

  • [1. 整体思路](#1. 整体思路)
  • [2. 完整代码](#2. 完整代码)
  • [3. 时空复杂度](#3. 时空复杂度)
      • [时间复杂度: O ( N ) O(N) O(N)](#时间复杂度: O ( N ) O(N) O(N))
      • [空间复杂度: O ( N ) O(N) O(N)](#空间复杂度: O ( N ) O(N) O(N))

1. 整体思路

核心问题

判断二叉树是否平衡。

算法逻辑

同样采用自底向上 的递归。

区别在于:

  1. 左子树优先检查
    • 先递归计算左子树的高度 l
    • 关键剪枝 :如果左子树返回 -1(说明左边已经不平衡了),那么整棵树肯定不平衡。此时不需要再递归计算右子树 ,直接向上返回 -1
  2. 右子树检查
    • 只有当左子树平衡(l != -1)时,才去递归计算右子树的高度 r
    • 如果右子树返回 -1,同样直接向上返回 -1
  3. 高度差检查
    • 如果左右子树都平衡,最后检查当前节点的左右高度差 Math.abs(l - r)
    • 如果超过 1,返回 -1
    • 否则返回当前高度 max(l, r) + 1

这种写法在遇到不平衡树时(特别是左子树就不平衡的情况),能够显著减少递归调用的次数。


2. 完整代码

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        // 调用 dfs,如果返回 -1 说明树不平衡
        return dfs(root) != -1;
    }

    private int dfs(TreeNode node) {
        // 递归终止条件:空节点高度为 0
        if (node == null) {
            return 0;
        }

        // 1. 先递归左子树
        int l = dfs(node.left);
        
        // 剪枝优化:如果左子树已经不平衡,直接返回 -1
        // 这一步避免了后续对右子树的递归调用 dfs(node.right)
        if (l == -1) {
            return -1;
        }

        // 2. 只有左子树平衡,才递归右子树
        int r = dfs(node.right);
        
        // 检查右子树是否不平衡,或者当前节点左右高度差是否 > 1
        // 如果任意条件满足,标记为不平衡 (-1)
        if (r == -1 || Math.abs(l - r) > 1) {
            return -1;
        }

        // 3. 左右子树都平衡且高度差 <= 1,返回当前节点高度
        return Math.max(l, r) + 1;
    }
}

3. 时空复杂度

假设二叉树节点数为 N N N。

时间复杂度: O ( N ) O(N) O(N)

  • 计算依据
    • 最坏情况下(整棵树是平衡的,或者不平衡发生在最右下角),我们需要遍历所有节点,每个节点访问一次。
    • 最好情况下(根节点的左子树直接就不平衡),我们只需要访问左子树的部分节点,甚至只访问常数个节点(如果树极度不平衡且偏左)。
    • 总体上仍是线性复杂度 O ( N ) O(N) O(N),但在平均情况下比无剪枝版本更快。
  • 结论 : O ( N ) O(N) O(N)。

空间复杂度: O ( N ) O(N) O(N)

  • 计算依据
    • 空间消耗主要来自递归栈。
    • 最坏情况(退化为链表): O ( N ) O(N) O(N)。
    • 平均/最好情况(平衡树): O ( log ⁡ N ) O(\log N) O(logN)。
  • 结论 : O ( N ) O(N) O(N)。
相关推荐
会员源码网1 天前
使用`mysql_*`废弃函数(PHP7+完全移除,导致代码无法运行)
后端·算法
木心月转码ing1 天前
Hot100-Day10-T438T438找到字符串中所有字母异位词
算法
HelloReader1 天前
Wi-Fi CSI 感知技术用无线信号“看见“室内的人
算法
颜酱1 天前
二叉树分解问题思路解题模式
javascript·后端·算法
qianpeng8971 天前
水声匹配场定位原理及实验
算法
董董灿是个攻城狮2 天前
AI视觉连载8:传统 CV 之边缘检测
算法
AI软著研究员2 天前
程序员必看:软著不是“面子工程”,是代码的“法律保险”
算法
FunnySaltyFish2 天前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
颜酱2 天前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法
地平线开发者3 天前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶