【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)。
相关推荐
鱼鱼不愚与2 小时前
《原来如此 | 第01期:为什么导航软件能预测红绿灯倒计时?》
算法
复杂网络7 小时前
论最小 Agent 计算机的形态
算法
kisshyshy1 天前
🍦 雪糕、食堂、火车厢:三幅漫画吃透栈、队列与链表
javascript·算法
猿人谷1 天前
不只是 CPU 阈值:STAR 如何用 GAT + Transformer 做容器级自动扩缩容?
人工智能·算法
复杂网络1 天前
Stable Diffusion 视觉大模型微调技术深度调研
算法
复杂网络1 天前
基于 Stable Diffusion 架构的视觉大模型代表性工作与原理深度解析
算法
MrZhao4001 天前
Agent Loop 如何用 Hook 扩展:权限、日志与工具拦截
算法
MrZhao4001 天前
Agent 为什么需要 Skills:别把所有知识都塞进 system prompt
算法
JieE2123 天前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
JieE2124 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试