【中等】力扣算法题解析LeetCode333:最大二叉搜索子树

关注文末推广名片,即可免费获得本题测试源码

题目来源:🔒 LeetCode 333:最大二叉搜索子树

问题抽象: 给定一个二叉树的根节点 root,要求找出该树中节点数量最多的子树,且该子树必须是二叉搜索树(BST),满足以下核心需求:

  1. 子树定义与性质

    • 子树包含当前节点、所有后代节点及其连接关系;
    • 目标子树需严格满足 BST 规则:
      • 左子树所有节点值 < 根节点值;
      • 右子树所有节点值 > 根节点值;
      • 左、右子树自身也必须是 BST。
  2. 优化目标

    • 在所有满足 BST 性质的子树中,选择包含节点数最多的子树;
    • 若存在多个相同大小的最大 BST 子树,返回任意一个均可。
  3. 边界处理

    • 空树(root = null)视为节点数为 0 的 BST;
    • 单节点树(无子树)视为有效 BST(节点数=1);
    • 子树必须完全独立于原树结构(即子树不能包含非后代节点)。

输入:二叉树根节点 root(节点值范围整型,树节点数 ≥ 0
输出:最大 BST 子树的节点数量(整数)。


解题思路

题目要求找出二叉树中最大的二叉搜索子树(BST),并返回其节点数。子树必须包含所有后代节点。我们采用后序遍历(DFS)自底向上处理每个节点,在递归过程中收集子树的关键信息,并判断当前子树是否为BST。

关键步骤

  1. 递归设计:每个递归返回一个包含4个属性的结果对象:

    • min:当前子树的最小值
    • max:当前子树的最大值
    • size:当前子树的节点总数
    • isBST:当前子树是否为BST
  2. 空节点处理:空节点返回特殊结果(min=MAX_VALUE, max=MIN_VALUE, size=0, isBST=true),避免影响父节点判断。

  3. BST判断条件

    • 左右子树均为BST
    • 当前节点值 > 左子树的最大值(左子树非空时)
    • 当前节点值 < 右子树的最小值(右子树非空时)
  4. 更新最大BST:若当前子树是BST,则用其节点数更新全局最大值。

  5. 非BST处理:仍需计算当前子树的min/max/size(用于父节点判断),但不更新全局最大值。


代码实现(Java版)

class Solution {
    private int maxSize = 0; // 全局变量记录最大BST节点数

    public int largestBSTSubtree(TreeNode root) {
        dfs(root);
        return maxSize;
    }

    private Result dfs(TreeNode node) {
        if (node == null) {
            return new Result(Integer.MAX_VALUE, Integer.MIN_VALUE, 0, true);
        }
        
        Result left = dfs(node.left);
        Result right = dfs(node.right);
        
        // 计算当前子树的最小值、最大值和节点总数
        int curMin = Math.min(node.val, Math.min(left.min, right.min));
        int curMax = Math.max(node.val, Math.max(left.max, right.max));
        int curSize = left.size + right.size + 1;
        
        boolean isBST = false;
        // 判断当前子树是否为BST
        if (left.isBST && right.isBST) {
            boolean leftValid = (left.size == 0) || (node.val > left.max);
            boolean rightValid = (right.size == 0) || (node.val < right.min);
            if (leftValid && rightValid) {
                isBST = true;
                maxSize = Math.max(maxSize, curSize); // 更新全局最大值
            }
        }
        return new Result(curMin, curMax, curSize, isBST);
    }

    // 内部类封装子树信息
    static class Result {
        int min;     // 子树最小值
        int max;     // 子树最大值
        int size;    // 子树节点总数
        boolean isBST; // 是否为BST
        
        Result(int min, int max, int size, boolean isBST) {
            this.min = min;
            this.max = max;
            this.size = size;
            this.isBST = isBST;
        }
    }
}

代码说明

  1. 全局变量maxSize 动态记录遍历过程中发现的最大BST节点数。
  2. 递归函数 dfs
    • 终止条件:节点为空时返回特殊Result对象。
    • 递归过程:先处理左右子树,再计算当前子树信息。
    • BST判断:通过检查左右子树状态及节点值关系确定当前子树是否为BST。
    • 更新逻辑:当前子树是BST时更新 maxSize
  3. Result类:封装子树的关键信息,便于递归传递。
  4. 边界处理
    • 空节点:min=MAX_VALUE, max=MIN_VALUE 确保不影响父节点比较。
    • 叶子节点:自动满足BST条件(节点数=1)。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

达文汐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值