98. 验证二叉搜索树(中等)
题目
给一棵二叉树的根节点 root,判断它是不是一棵合法的二叉搜索树(BST)。合法需要同时满足三点:
- 左子树中所有节点的值都严格小于当前节点的值;
- 右子树中所有节点的值都严格大于当前节点的值;
- 左、右子树本身也必须各自是一棵合法的 BST。
自造非法示例:层序数组 [10,5,15,null,null,6,20] 应返回 false。单看 15 的左孩子 6,确实满足 6 < 15;但 6 位于根节点 10 的右子树中,必须大于 10,实际却小于 10,因此整棵树不合法。
自造合法示例:层序数组 [4,2,6,1,3,5,7] 应返回 true——每个节点都落在它所有祖先逐步划定的允许范围内。
约束:节点数 1 ~ 104;节点值在 32 位有符号整数范围内;树节点结构见下文代码。
思路
一句话:BST 的“合法”不是父子之间的局部比较,而是每个节点都要满足所有祖先留下的全局约束。
先想最直白的做法:对每个节点只检查 左孩子 < 自己 < 右孩子。它为什么不够?因为它只看一层父子关系,管不住更上面的祖先。前面 [10,5,15,null,null,6,20] 的例子就说明了这一点:6 比父亲 15 小,却违反了“必须大于祖先 10”的约束。
更严格但笨的做法是:对每个节点都去扫一遍它的左子树,确认所有值都小于它;再扫一遍右子树,确认所有值都大于它。这样每个节点可能被多个祖先重复检查,总代价会到 O(n²),明显不划算。
关键观察:BST 的合法性有两条等价刻画:
- 中序遍历严格递增。 按「左 → 根 → 右」访问 BST,得到的值序列必然从小到大排列;反过来,如果中序序列严格递增,那么这棵树也一定是 BST。
- 每个节点都有一个允许值区间。 从根开始,根的可取范围是
(-∞, +∞);往左走时,父节点的值成为新的上界;往右走时,父节点的值成为新的下界。
两条路都能一次遍历完成。本文主推区间递归:它最贴合题目“左子树全部小于、右子树全部大于”的字面定义,也最好记。
解法
定义辅助函数 valid(node, low, high),表示判断以 node 为根的子树是否完全落在开区间 (low, high) 内:
- 若
node为空,返回true,空树视为合法。 - 若
node.val不满足low < node.val < high,返回false。 - 递归检查左子树,上界收紧为当前值:
valid(node.left, low, node.val)。 - 递归检查右子树,下界收紧为当前值:
valid(node.right, node.val, high)。 - 左右都合法,整棵子树才合法;根节点入口调用
valid(root, -∞, +∞)。
以合法树 [4,2,6,1,3,5,7] 为例,区间从根向下逐渐收紧:
| 节点 | 允许区间 | 区间怎么来的 |
|---|---|---|
| 4(根) | (-∞, +∞) | 根节点没有祖先约束 |
| 2(4 的左孩子) | (-∞, 4) | 进入左子树,父节点值变上界 |
| 1(2 的左孩子) | (-∞, 2) | 继续往左,上界继续收紧 |
| 3(2 的右孩子) | (2, 4) | 从 2 往右,下界为 2,上界仍为 4 |
| 6(4 的右孩子) | (4, +∞) | 进入右子树,父节点值变下界 |
| 5(6 的左孩子) | (4, 6) | 从 6 往左,上界收紧为 6 |
7(6本篇为付费内容您已阅读试读部分,购买后即可解锁全文。 ⚠️ 本站内容已做唯一性标记并受版权保护,未经授权禁止转载,侵权必究。 |
还没有评论,来说两句?