三种思路彻底掌握 BST 判断(递归与迭代全解析)——力扣98.验证二叉搜索树

力扣98.验证二叉搜索树


一、题目描述

给定一个二叉树的根节点 root,判断它是否是一棵有效的二叉搜索树(BST)。

有效二叉搜索树的定义:

  1. 节点的左子树只包含严格小于当前节点的值;
  2. 节点的右子树只包含严格大于当前节点的值;
  3. 所有左子树和右子树本身也必须是二叉搜索树。

示例 1:

复制代码
输入:root = [2,1,3]
输出:true

示例 2:

复制代码
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5,但其右子树中的节点 4 小于 5。

提示:

  • 节点总数范围:1, 10⁴
  • 节点值范围:-2³¹, 2³¹ - 1

二、思路分析

判断是否为二叉搜索树,本质上有两种思路:

  1. 区间递归法: 每个节点的值必须在一个动态变化的 (min, max) 范围内;
  2. 中序遍历法: 二叉搜索树的中序遍历序列应严格递增。

这两种思路都能达到 O(n) 的时间复杂度,区别在于递归参数设计与思维方式不同。


三、解法一:递归区间法(Top-Down)

核心思想:

从根节点开始,为每个节点维护一个允许取值的上下界:

  • 对左子树而言,最大值应为当前节点值;
  • 对右子树而言,最小值应为当前节点值。

若某个节点值不在范围内,则立即返回 false。

代码实现:

java 复制代码
class Solution {
    public boolean isValidBST(TreeNode root) {
        return validate(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    private boolean validate(TreeNode node, long min, long max) {
        if (node == null) return true;
        if (node.val <= min || node.val >= max) return false;
        return validate(node.left, min, node.val) 
            && validate(node.right, node.val, max);
    }
}

复杂度分析:

  • 时间复杂度:O(n),每个节点访问一次;
  • 空间复杂度:O(h),h 为树的高度(最坏 O(n))。

思维亮点:

  • 使用 long 避免边界越界;
  • "上下界随递归动态变化"的设计思路极具通用性。

四、解法二:中序遍历法(Inorder Traversal)

核心思想:

二叉搜索树的中序遍历结果是一个严格递增序列。

因此,只需在遍历过程中比较当前节点值是否大于前一个节点值即可。

代码实现:

java 复制代码
class Solution {
    private long prev = Long.MIN_VALUE;

    public boolean isValidBST(TreeNode root) {
        if (root == null) return true;
        if (!isValidBST(root.left)) return false;
        if (root.val <= prev) return false;
        prev = root.val;
        return isValidBST(root.right);
    }
}

复杂度分析:

  • 时间复杂度:O(n)
  • 空间复杂度:O(h)

思维亮点:

  • 利用 BST 的中序有序性质;
  • 实现极为简洁,逻辑清晰。

五、解法三:迭代中序法(使用显式栈)

核心思想:

用栈模拟中序遍历过程,每次取出最左节点,与前驱节点比较。

代码实现:

java 复制代码
import java.util.Stack;

class Solution {
    public boolean isValidBST(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        TreeNode curr = root;
        long prev = Long.MIN_VALUE;

        while (curr != null || !stack.isEmpty()) {
            while (curr != null) {
                stack.push(curr);
                curr = curr.left;
            }
            curr = stack.pop();
            if (curr.val <= prev) return false;
            prev = curr.val;
            curr = curr.right;
        }
        return true;
    }
}

复杂度分析:

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

思维亮点:

  • 无递归调用栈;
  • 适合面试场景手写;
  • 清晰体现中序遍历过程。

六、方法对比总结

方法 思路核心 实现方式 是否递归 是否利用中序有序性 时间复杂度 空间复杂度 特点
区间递归法 动态上下界限制 递归 ✅ ❌ O(n) O(h) 思维直观、通用性强
中序递归法 严格递增序列 递归 ✅ ✅ O(n) O(h) 简洁优雅、代码最短
迭代中序法 栈模拟中序 迭代 ❌ ✅ O(n) O(n) 面试友好、结构清晰

扩展思考:

  • 若想要"找到二叉搜索树中的第 k 小节点",可以在中序遍历中计数;
  • 若想"修复错误的二叉搜索树",也可以利用中序递增特性定位错误节点。

相关推荐
yi01113 分钟前
LeetCode 3. 无重复字符的最长子串|不定长滑动窗口:什么时候更新最大值?
笔记·python·算法·leetcode·双指针·滑动窗口
y1su20 分钟前
Leetcode 单调栈模板
java·开发语言·数据结构·算法·leetcode
索尔~古德曼35 分钟前
CF(1400-1400&1300-1500)
算法
爱刷碗的苏泓舒42 分钟前
泰勒级数与泰勒展开:GNSS卫地距线性化、Jacobian矩阵与Hessian矩阵
线性代数·算法·矩阵·gnss·雅可比矩阵·卫地距线性化·海森矩阵
垆边人似月.1 小时前
华为题:每日温度
数据结构·c++·算法
Sylvia-girl1 小时前
堆排序算法
算法·排序算法·c
Peregrine91 小时前
数据结构 - > 树和二叉树
数据结构·算法
我是人✓1 小时前
Java面向对象核心特性深度解析
java·前端·算法
j7~1 小时前
【算法】专题四.前缀和:一维二维模板,配套 LeetCode 真题,结合同余定理、哈希前缀和,搞定子数组与子矩阵区间求和问题。
数据结构·c++·算法·前缀和·优选算法
看浪的路人1 小时前
第1讲:2026 大模型应用开发全景——Prompt / RAG / 微调 / Agent 到底先用哪个
人工智能·算法