算法 - 验证二叉搜索树
1. 题目
给你一个二叉树的根节点 root,判断其是否是一个有效的二叉搜索树(BST)。
有效 BST 定义:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例:
1 | 输入: root = [5,1,4,null,null,3,6] |
2. 解题思路
2.1 常见错误:只比较父子
只判断「左子 < 父 < 右子」是不够的——如上图,节点 3 是其父 4 的合法左子,但它位于根 5 的右子树中,必须 > 5。约束是从根一路传递下来的区间。
2.2 上下界递归(正确)
给每个节点维护一个开区间 (min, max):
根的区间是
(-∞, +∞)。走向左孩子:上界收紧为父节点值 →
(min, node.val)。走向右孩子:下界收紧为父节点值 →
(node.val, max)。节点值必须严格落在自己区间内,否则非法。
时间复杂度:O(n),空间复杂度:O(h)。
2.3 中序遍历递增
BST 的中序遍历结果严格递增。迭代中序遍历,比较当前值与前驱值 prev,若 val <= prev 则非法。用 prev 记录上一个访问值即可,天然利用「左→根→右」顺序。
- 时间复杂度:O(n),空间复杂度:O(h)。
3. TypeScript 实现
树节点定义:
1 | class TreeNode { |
3.1 上下界递归
1 | function isValidBST(root: TreeNode | null): boolean { |
3.2 中序遍历(迭代)
1 | function isValidBSTInorder(root: TreeNode | null): boolean { |
4. 面试延伸
- 为什么用严格
<、>(而非<=):BST 定义里子树值必须严格小于/大于,相等也算非法;用Infinity做初始边界可避免「节点值恰好等于 INT_MIN/INT_MAX」的坑(用null表示无边界更稳妥)。 - 传递区间 vs 传递父指针:区间法最直观;中序法把「树问题」转成「有序序列问题」是常用思维。
- 关联题:BST 第 k 小、把有序数组转 BST、LCA of BST 都依赖「中序有序」或「值域可二分」性质。
难度:中等 | LeetCode 98 | BST 性质 / 遍历