← 返回编程题库
coding-validate-bst-recursive简单免费版2000ms未尝试

校验二叉搜索树(递归区间)

Validate Binary Search Tree (Recursive Bounds)

开始编码

二叉搜索树(BST) 是这样一种二叉树:每个节点的键严格大于左子树中所有键,且严格小于右子树中所有键。给你一棵以嵌套字典编码的二叉树,判断它是否满足该性质。

请实现 solution(tree: dict | None) -> bool,当且仅当 tree 是合法 BST 时返回 True。树编码方式:

  • 空树None
  • 叶子{"is_leaf": True, "value": <int>},只有这两个键。
  • 内部节点{"is_leaf": False, "value": <int>, "left": <subtree | None>, "right": <subtree | None>}

标准递归思路是把 (min_bound, max_bound) 区间沿树向下传递:每个节点的 value 必须满足 min_bound < value < max_bound;递归 left 时把上界收紧为当前 value,递归 right 时把下界收紧为当前 value,根节点初始用 (-inf, +inf)。等于边界即违反——BST 使用严格不等。

示例

solution(None) 返回 True。空树按惯例视为合法 BST。

solution({"is_leaf": False, "value": 5, "left": {"is_leaf": True, "value": 3}, "right": {"is_leaf": True, "value": 8}}) 返回 True。深度-1 的树,3 < 5 < 8,每个孩子都满足严格区间。

solution({"is_leaf": False, "value": 2, "left": {"is_leaf": True, "value": 0}, "right": {"is_leaf": True, "value": 1}}) 返回 False。右子节点是 1,但 root=2 的右子树必须严格大于 2。这就是 LeetCode 98 的经典反例。

实战背景

BST 校验远不止是教科书里的树练习。一个具体的交易场景:很多决策引擎、风险引擎的代码路径会把一张排序好的阈值表存成一棵小型内存树(对延迟敏感的「这个值落在哪个桶」查询),构建该树的流水线需要在把它推上生产之前确认结果确实是一棵合法 BST——一棵被悄悄破坏的阈值树会以「看起来像模型 bug、其实是数据 bug」的形态错分订单或风险敞口。同样的原语也用来校验任何排序/有序的树形索引:order book 价格层级树、缓存为平衡 BST 的价格阶梯、训练后导出待上线前要做 sanity-check 的决策树模型。区间递归这套思路可以无痛迁移:把「严格 <」换成你领域需要的序关系(多重集允许 <=、元组键用字典序、币种感知的价格键用自定义比较器),同一份骨架就能校验对应的结构不变量。

约束条件

  • 每个节点是字典。叶子:`{"is_leaf": true, "value": <int>}`,仅这两个键(没有 `left`/`right`)。内部节点:`{"is_leaf": false, "value": <int>, "left": <subtree | null>, "right": <subtree | null>}`。
  • `tree` 可能为 `None`(空树);按惯例空树视为合法 BST,返回 `True`。
  • 内部节点的 `left`/`right` 各自可以是 `None`(缺失子树)或另一个节点字典。
  • BST 使用**严格不等**:左子树中每个值必须 `< node.value`,右子树中每个值必须 `> node.value`,相等即违反。
  • 树深度 ≤ 50。`value` 为整数(初始上下界用 `float('-inf')`/`float('inf')` 或任何能压过所有整数的哨兵都可以)。

样例

Case 1 · empty tree (None) is a valid BST

输入: [null]

期望: true

空树(None)按惯例视为合法 BST。这条用例确认你在 `tree is None` 时直接返回 True,而不是去访问字段触发 KeyError。

Case 2 · single-node leaf is a valid BST

输入: [{"is_leaf":true,"value":7}]

期望: true

只有一个叶子节点的树没有「左 < 根 < 右」的约束可违反,永远合法。这条用例考察你能正确处理 `is_leaf=true` 的叶子节点(叶子节点没有 left/right 键,不能直接索引)。

Case 3 · depth-1 valid BST: left<root<right

输入: [{"is_leaf":false,"value":5,"left":{"is_leaf":true,"value":3},"right":{"is_leaf":true,"value":8}}]

期望: true

标准的深度-1 合法 BST:根 5,左子 3,右子 8。3 < 5 < 8 满足 BST 约束。这是最朴素的正例。

Case 4 · violation: right child smaller than root (2.right=1)

输入: [{"is_leaf":false,"value":2,"left":{"is_leaf":true,"value":0},"right":{"is_leaf":true,"value":1}}]

期望: false

经典反例:根=2,右子=1。1 在右子树却小于根 2,违反 BST 性质。这道题专门考察「右子必须严格大于祖先」——也是 LeetCode 98 一道很常见的陷阱。

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · empty tree (None) is a valid BST

输入: [null]

期望: true

空树(None)按惯例视为合法 BST。这条用例确认你在 `tree is None` 时直接返回 True,而不是去访问字段触发 KeyError。

Case 2 · single-node leaf is a valid BST

输入: [{"is_leaf":true,"value":7}]

期望: true

只有一个叶子节点的树没有「左 < 根 < 右」的约束可违反,永远合法。这条用例考察你能正确处理 `is_leaf=true` 的叶子节点(叶子节点没有 left/right 键,不能直接索引)。

Case 3 · depth-1 valid BST: left<root<right

输入: [{"is_leaf":false,"value":5,"left":{"is_leaf":true,"value":3},"right":{"is_leaf":true,"value":8}}]

期望: true

标准的深度-1 合法 BST:根 5,左子 3,右子 8。3 < 5 < 8 满足 BST 约束。这是最朴素的正例。

Case 4 · violation: right child smaller than root (2.right=1)

输入: [{"is_leaf":false,"value":2,"left":{"is_leaf":true,"value":0},"right":{"is_leaf":true,"value":1}}]

期望: false

经典反例:根=2,右子=1。1 在右子树却小于根 2,违反 BST 性质。这道题专门考察「右子必须严格大于祖先」——也是 LeetCode 98 一道很常见的陷阱。