当前位置: 首页 > news >正文

【LeetCode 热题 100】98. 验证二叉搜索树——(解法一)前序遍历

Problem: 98. 验证二叉搜索树
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(N)
    • 空间复杂度:O(H)

整体思路

这段代码旨在解决一个经典的树形结构问题:验证二叉搜索树 (Validate Binary Search Tree)。其目标是判断一棵给定的二叉树是否是有效的二叉搜索树(BST)。

一个有效的BST必须满足以下三个条件:

  1. 节点的左子树只包含键 小于 节点键的节点。
  2. 节点的右子树只包含键 大于 节点键的节点。
  3. 左右子树也必须分别是二叉搜索树。

仅仅检查 node.left.val < node.valnode.right.val > node.val不够的。因为一个节点的值不仅要和它的父节点比较,还必须满足其所有祖先节点施加的约束。例如,在一个节点的右子树中,所有节点的值都必须大于该节点的父节点的值,也要大于其祖父节点的值(如果该节点在祖父的右子树中)。

该算法采用了一种非常优雅且正确的 递归(深度优先搜索,DFS) 方法,通过传递有效值范围来解决这个问题。

  1. 核心思想:约束范围 (Constraint Propagation)

    • 算法的核心思想是,对于树中的每一个节点,它不仅自身的值有要求,它还会对它的子树施加新的约束。
    • 具体来说,当递归到一个节点 node 时,我们不仅检查它自身的值,还会将它的值作为新的边界传递给它的子节点。
    • 对于 node左子树,所有节点的值都必须小于 node.val。所以,node.val 成为了左子树的上界 (right bound)
    • 对于 node右子树,所有节点的值都必须大于 node.val。所以,node.val 成为了右子树的下界 (left bound)
  2. 递归与边界传递

    • 算法的主体是一个递归函数 dfs(node, left, right),它负责验证以 node 为根的子树是否是有效的BST,并且子树中所有节点的值都必须在开区间 (left, right) 内。
    • 数据类型选择:使用 long 类型的 leftright 是为了处理边界情况,即当节点的 val 恰好是 Integer.MIN_VALUEInteger.MAX_VALUE 时,普通的 int 无法表示比它更小或更大的边界。
    • 递归步骤
      a. 基本情况 (Base Case):如果 nodenull,空树被认为是有效的BST,直接返回 true
      b. 当前节点校验:检查当前节点的值 x = node.val 是否满足从父节点继承来的约束,即 x > left 并且 x < right。如果不满足,整棵树就不是BST,直接返回 false
      c. 递归校验子树:如果当前节点校验通过,则继续递归地检查左右子树,并传递更新后的约束
      • 左子树:调用 dfs(node.left, left, x)。左子树的下界 left 不变,但上界更新为当前节点的值 x
      • 右子树:调用 dfs(node.right, x, right)。右子树的上界 right 不变,但下界更新为当前节点的值 x
        d. 结果合并:只有当当前节点左子树右子树都有效时,以 node 为根的子树才被认为是有效的。&& 逻辑与操作完美地实现了这一点。

完整代码

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {/*** 判断给定的二叉树是否是一个有效的二叉搜索树(BST)。* @param root 二叉树的根节点* @return 如果是有效的BST则返回 true,否则返回 false*/public boolean isValidBST(TreeNode root) {// 初始调用,根节点的有效范围是 (Long.MIN_VALUE, Long.MAX_VALUE),即整个long类型的范围。// 使用 long 类型是为了防止节点的 val 恰好是 Integer.MIN_VALUE 或 Integer.MAX_VALUE 时,// 边界 int 类型无法表示比它更小或更大的数。return dfs(root, Long.MIN_VALUE, Long.MAX_VALUE);}/*** 递归辅助函数,验证以 node 为根的子树是否是有效的BST,* 并且其所有节点值都在开区间 (left, right) 内。* @param node 当前要验证的节点* @param left 允许的最小值(不包含)* @param right 允许的最大值(不包含)* @return 如果子树有效且满足范围约束,则返回 true*/private boolean dfs(TreeNode node, long left, long right) {// 基本情况:空树是有效的BSTif (node == null) {return true;}// 获取当前节点的值long x = node.val;// 核心逻辑:// 1. 检查当前节点值 x 是否在 (left, right) 区间内。// 2. 递归检查左子树,并更新上界为 x。左子树所有节点必须在 (left, x) 区间内。// 3. 递归检查右子树,并更新下界为 x。右子树所有节点必须在 (x, right) 区间内。// 只有这三个条件都满足时,才返回 true。return x < right && x > left && dfs(node.left, left, x) && dfs(node.right, x, right);}
}

时空复杂度

时间复杂度:O(N)

  1. 节点访问:算法通过深度优先搜索(DFS)的方式,访问了树中的每一个节点,并且每个节点只被访问一次。
  2. 递归函数调用dfs 函数对每个节点调用一次。在函数内部,执行的都是常数时间的比较和逻辑运算。
  3. 综合分析
    • 设树中共有 N 个节点。每个节点都被访问一次,并进行 O(1) 的操作。
    • 因此,总的时间复杂度与节点总数成正比,为 O(N)

空间复杂度:O(H)

  1. 主要存储开销:算法的额外空间主要由递归调用栈所占用。
  2. 递归深度:递归的最大深度取决于树的高度 H
    • 最好情况:如果树是高度平衡的,其高度 H 约为 log N。此时空间复杂度为 O(log N)
    • 最坏情况:如果树是极度不平衡的(例如,退化成一个链表),其高度 H 将等于节点数 N。此时空间复杂度为 O(N)

综合分析
该算法的(辅助)空间复杂度由递归栈的深度决定,因此为 O(H),其中 H 是树的高度。

【LeetCode 热题 100】98. 验证二叉搜索树——(解法二)中序遍历

参考灵神

http://www.lryc.cn/news/586088.html

相关文章:

  • 初等行变换会改变矩阵的什么?不变改变矩阵的什么?求什么时需要初等行变换?求什么时不能初等行变换?
  • 【Go + Gin 实现「双 Token」管理员登录】
  • Linux/Ubuntu安装go
  • 客户资源被挖?营销方案泄露?企业经营信息保护避坑指南
  • Day 3·知识卡片|Python基础:print 函数还能这么玩?
  • 阿里开源AI大模型ThinkSound如何为视频配上灵魂之声
  • Windows X64环境下mysql5.6.51安装指南
  • SpringBootloggers未授权访问漏洞处理
  • 基于MCP的CI/CD流水线:自动化部署到云平台的实践
  • Unity VR手术模拟系统架构分析与数据流设计
  • JVM 中“对象存活判定方法”全面解析
  • 同步、异步、阻塞、非阻塞之间联系与区别
  • Windows符号链接解决vscode和pycharm占用C盘空间太大的问题
  • [论文阅读] 人工智能 + 软件工程 | AI助力软件可解释性:从用户评论到自动生成需求与解释
  • 利用scale实现分页按钮,鼠标经过按钮放大
  • 12.使用VGG网络进行Fashion-Mnist分类
  • 解决bash终端的路径名称乱码问题
  • java单例设计模式
  • pip国内镜像源一览
  • 高校/企业/医院食堂供应链平台开发详解:采购系统源码的核心价值
  • MySQL 中图标字符存储问题探究:使用外挂法,毕业论文——仙盟创梦IDE
  • Oxygen XML Editor 26.0编辑器
  • 车载诊断架构 --- 诊断功能开发流程
  • Operation Blackout 2025: Smoke Mirrors
  • 日志不再孤立!用 Jaeger + TraceId 实现链路级定位
  • 传感器WSNs TheDataLinkLayer——X-MAC
  • 前端开发中的输出问题
  • try-catch-finally可能输出的答案?
  • [BUUCTF 2018]Online Tool
  • MCP上的数据安全策略:IAM权限管理与数据加密实战