跳到正文
第 98 题中等

验证二叉搜索树

Validate Binary Search Tree

判断一棵二叉树是否为有效的二叉搜索树。

在力扣中练习

题目描述

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 严格小于 当前节点的数。
  • 节点的右子树只包含 严格大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

 

示例 1:

输入:root = [2,1,3]
输出:true

示例 2:

输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

 

提示:

  • 树中节点数目范围在[1, 104] 内
  • -231 <= Node.val <= 231 - 1

解题思路

主解法

上下界 · 递归检查

每个节点都要满足整条祖先链给出的开区间

最直觉的错误写法是“每个节点只和左右孩子比较”。下面这棵树就是反例:9 确实大于父节点 4,但 4 是 8 的左孩子,9 出现在 4 的右子树里就越过了祖先 8 的上界。

分步图解

根节点没有上下界,允许区间是 (-∞, +∞);检查会带着区间向下递归。

每个节点只能落在祖先给出的开区间内左子树 · 右子树
8412291014
当前允许区间 (low, high)
low=-∞val=—high=+∞
1 / 3
每下一层都收紧一侧边界;节点要和整条祖先链比较。

正确做法是带着区间递归:根的范围是 (-∞, +∞);进入左子树时上界收紧为当前值,进入右子树时下界收紧为当前值。节点必须严格落在 (low, high) 内。

用节点指针做边界,可以避免 INT_MIN/INT_MAX 被节点值占用的问题;也可以改用 long long。

分步图解

节点 4 落在 (-∞, 8) 内;左孩子上界收紧为 4,右孩子下界收紧为 4。

每个节点只能落在祖先给出的开区间内左子树 · 右子树
8412291014
当前允许区间 (low, high)
low=-∞val=4high=8
1 / 3
9 大于父节点 4,但 8 给出的上界不允许它出现在右子树里。

自拟树中 9 只和父节点 4 比较是合法的,但 8 给出的上界把它拦住了。每个节点只访问一次,时间 O(n)。

时间 O(n)空间 O(h)

易错点

  • 只比较 node 与左右孩子:无法发现“越过祖先”的节点。
  • 把区间写成闭区间:BST 通常不允许重复值,等于边界也非法。
  • 用 INT_MIN/INT_MAX 当初始边界:节点值恰好等于极值时误判。
对照解法

中序遍历 · 严格递增

BST 的中序序列必须严格递增

同样 O(n),但需要 O(h) 显式栈;递归上下界更容易在访问时立刻定位错误。

利用 BST 的定义:中序遍历会得到严格递增的序列。只要在遍历时记录前一个访问的节点,发现 prev->val >= cur->val 就返回 false。

迭代中序用栈实现,不需要额外数组;也可以在递归中维护 prev。

这个方法把“整棵树是否有序”转化为“相邻元素是否有序”,非常简洁,但如果不熟悉中序迭代模板,容易在栈和 cur 的移动上写错。

  1. 1沿左链压栈,弹出即访问。
  2. 2比较当前值与上一个访问值。
  3. 3不满足严格递增返回 false。
  4. 4遍历结束返回 true。
时间 O(n)空间 O(h)

易错点

  • 用 <= 比较而不是 >=:重复值会被误判为合法。
  • prev 只在递归返回时更新:比较的就不是中序前驱。

代码与演示

主解法配有图解;对照解法用于比较思路、复杂度或实现方式。

演示输入root = [8,4,12,2,9,10,14]

根节点没有上下界,允许区间是 (-∞, +∞);检查会带着区间向下递归。

每个节点只能落在祖先给出的开区间内左子树 · 右子树
8412291014
当前允许区间 (low, high)
low=-∞val=—high=+∞
1 / 5
查看 C++ 代码

延伸阅读

  • BST 的判定必须使用“祖先区间”,不能只看父子关系;同理,删除/插入节点也要维护区间。
  • 中序严格递增是等价的判定方式,很多 BST 题都可以先转成中序序列思考。