题目描述

✅ 面试题 04.05. 合法二叉搜索树

image-20260929105754988

题意分析

判断二叉树是否满足严格搜索树规则:每个节点左子树中的全部节点都比它小,右子树中的全部节点都比它大,并且左右子树也分别合法。约束会作用于更深的后代,因此只比较直接父子节点不够,重复值也不能通过。

解法:DFS 区间校验

核心思路

[!blue]
用一个开区间同时携带所有祖先的约束。 dfs(node, lower, upper) 检查以 node 为根的子树能否放在值域 (lower, upper) 中。进入该子树的每个节点都必须满足 lower < val < upper;下界概括了必须大于的祖先,上界概括了必须小于的祖先。

当前节点通过范围检查后,递归左子树时把上界改成当前值,保留下界;递归右子树时把下界改成当前值,保留上界。由于当前值已经位于原区间内部,新区间只会收窄,不会放松任何祖先限制。这样每个后代都同时接受当前位置的限制与全部继承限制。

若某个值等于边界或越过边界,就违反了严格大小关系,立即失败。空节点没有需要检查的值,返回真;当前值合法且两个子树都通过时,才返回真。左右结果用短路与连接,一侧失败便无需继续另一侧。

初始范围必须容纳所有合法节点值。节点值使用 32 位整数范围,而边界使用 64 位整数极值;这样合法的最小、最大节点值都严格位于初始范围内,也无需通过加减 1 调整边界,避免端点溢出。

解题步骤

  1. 以宽整数的最小、最大值作为初始边界。
  2. 空节点直接通过。
  3. 当前值小于等于下界,或大于等于上界,都返回 false。
  4. 左子树递归范围为 (lower, val),右子树为 (val, upper),两边同时通过才返回 true。空树自然合法,单节点树只需通过一次范围检查。

代码实现

class Solution {
    public boolean isValidBST(TreeNode root) {
        return dfs(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    private boolean dfs(TreeNode node, long lower, long upper) {
        if (node == null) {
            return true;
        }

        // 开区间携带全部祖先约束,触碰边界也不合法。
        if (node.val <= lower || node.val >= upper) {
            return false;
        }

        return dfs(node.left, lower, node.val) && dfs(node.right, node.val, upper);
    }
}
func isValidBST(root *TreeNode) bool {
    return dfs(root, -1<<63, 1<<63-1)
}

func dfs(node *TreeNode, lower int64, upper int64) bool {
    if node == nil {
        return true
    }
    v := int64(node.Val)
    // 开区间携带全部祖先约束,触碰边界也不合法。
    if v <= lower || v >= upper {
        return false
    }
    return dfs(node.Left, lower, v) && dfs(node.Right, v, upper)
}

复杂度分析

  • 时间复杂度:最坏 $O(n)$,每个节点至多检查一次。
  • 空间复杂度:$O(h)$,递归栈由树高决定。

关键点总结

[!green]

  • 边界来自全部祖先,不只是父节点。
  • 严格大小关系用开区间表达,重复值不能通过。
  • 哨兵要位于合法节点值域之外。

易错点总结

[!yellow]

  • 只比较节点与直接孩子:漏掉更深后代对祖先的违反。
  • 递归时不收窄边界:祖先约束没有传下去。
  • 允许等于边界:重复值被误判合法。
  • 使用 int 极值作为开区间哨兵:真实端点值会被排除。

相似题目

题目 难度 关联与区别
99. 恢复二叉搜索树 中等 原题BST有两个值被交换,需要定位中序逆序点,本题只检查结构和值是否满足严格有序。
700. 二叉搜索树中的搜索 简单 BST查找依赖全局有序约束,本题验证该约束不能只比较父子局部值。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2022/30750184
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!