98.Validate_Binary_Search_Tree

25 年 7 月 2 日 星期三
941 字
5 分钟

98. Validate Binary Search Tree

Screenshot 2026-03-07 at 3.33.53 pm
js
var isValidBST = function (root) {
  // 初始化前驱节点的值为负无穷,用于记录中序遍历的上一个节点值
  // 选择负无穷是因为二叉树节点值可能包含任意整数(包括极小值)
  let pre = -Infinity

  /**
   * 深度优先搜索(DFS)的递归函数,执行中序遍历并验证升序特性
   * @param {TreeNode} node - 当前遍历的节点
   * @returns {boolean} - 当前子树是否满足BST条件
   */
  function dfs(node) {
    // 递归终止条件:遇到空节点,空树/空子树默认是有效的BST
    if (node == null) {
      return true
    }

    // 1. 遍历左子树(中序遍历:左)
    // 如果左子树不满足BST条件,直接返回false,无需继续遍历
    if (!dfs(node.left)) {
      return false
    }

    // 2. 处理当前节点(中序遍历:中)
    // 核心验证逻辑:BST要求当前节点值必须严格大于前驱节点值
    // 若当前节点值 <= 前驱节点值,说明不满足BST特性,返回false
    if (node.val <= pre) {
      return false
    }
    // 更新前驱节点值为当前节点值,供后续右子树验证使用
    pre = node.val

    // 3. 遍历右子树(中序遍历:右)
    // 右子树的验证结果直接返回(若右子树不满足,整体就不满足)
    return dfs(node.right)
  }

  // 从根节点开始执行中序遍历验证
  return dfs(root)
}

举个反例

考虑下面这棵树:

text
      10
     /  \
    5    15
        /  \
       6    20
  • 按你的代码逻辑:
    1. 在根节点 10 处,5<10 且 15>10 ✅,再分别递归检查子树;
    2. 对子树根 15,6<15 且 20>15 ✅,再递归检查它们都是叶子也都返回 True;
    3. 整棵树被判作合法 BST。
  • 但实际上,节点 6 在 10 的右子树中,却 6<10,违背了 BST 要求“右子树所有节点都 > 10”的规则。

正确思路

要验证一棵树是不是 BST,必须对每个节点维护一个上下界(lower < node.val < upper):

python
def isValidBST(root):
    def helper(node, lower, upper):
        if not node:
            return True
        val = node.val
        # 如果超出允许区间,立刻 False
        if val <= lower or val >= upper:
            return False
        # 左子树所有节点必须 < val;右子树所有节点必须 > val
        return helper(node.left, lower, val) and \
               helper(node.right, val, upper)

    # 整棵树任意值都要在 (-∞, +∞) 之间
    return helper(root, float('-inf'), float('inf'))

这样,访问到节点 6 时,它所在的调用栈里 lower=10upper=15,会被马上判为 False。


另一种简洁做法:中序遍历

因为 BST 的 中序遍历结果一定是一个严格递增的序列,我们也可以这样写:

python
def isValidBST(root):
    prev = float('-inf')

    def inorder(node):
        nonlocal prev
        if not node:
            return True
        if not inorder(node.left):
            return False
        # 这里要严格大于前一个值
        if node.val <= prev:
            return False
        prev = node.val
        return inorder(node.right)

    return inorder(root)

这两种方法都能正确处理“深层子孙节点违反祖先约束”的情况,你可以根据习惯任选其一。

二叉搜索树

image-20250702225743958

前序遍历(preorder traversal)

python
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isValidBST(self, root: Optional[TreeNode], left=-inf, right=inf) -> bool:
        if not root:
            return True
        x = root.val
        return left < x < right and self.isValidBST(root.left, left, x) and self.isValidBST(root.right, x, right)

先访问节点,再遍历左右子树

思路:给isValidBST 加上left和right两个参数,二叉搜索树的左子树区间在(left, x.val) 之间,右子树同理。

中序遍历(inorder)

python
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    pre = -inf
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return True
        # check left child
        if not self.isValidBST(root.left):
            return False
        # 不能写成 val > self.pre return Ture
        # 不然会直接返回True
        if root.val <= self.pre:
            return False
        self.pre = root.val
        return self.isValidBST(root.right)

后序遍历(postorder)

image-20250703170847485

文章标题:98.Validate_Binary_Search_Tree

文章作者:Sirui Chen

文章链接:https://blog.siruichen.me/posts/98validate_binary_search_tree[复制]

最后修改时间:


商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,您可以自由地在任何媒体以任何形式复制和分发作品,也可以修改和创作,但是分发衍生作品时必须采用相同的许可协议。
本文采用CC BY-NC-SA 4.0进行许可。