当前位置: 首页 > 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.dtcms.com/a/275996.html

相关文章:

  • Python 三大高频标准库实战指南——json · datetime · random 深度解析
  • 【Java入门到精通】(二)Java基础语法(上)
  • 27. 移除元素
  • 【android bluetooth 协议分析 07】【SDP详解 1】【SDP 介绍】
  • 19th Day| 530.二叉搜索树的最小绝对差,501.二叉搜索树中的众数, 236.二叉树的最近公共祖先
  • springboot3X 整合高版本mybatisplus
  • pyqt5绘制矩形和线条
  • 【从零开始编写数据库:基于Python语言实现数据库ToyDB的ACID特性】
  • C语言<数据结构-单链表>(收尾)
  • Windows 开启和关闭 Administrator 用户的方法
  • 软考高级系系统分师和架构师常考知识点总结三
  • Typecho博客系统与WebSocket实时通信整合指南
  • 网络安全初级--搭建
  • GPU编程入门:CUDA与OpenCL全面解析
  • 聊下easyexcel导出
  • 岛屿数量问题
  • [爬虫实战] 多进程/多线程/协程-异步爬取豆瓣Top250
  • 小架构step系列12:单元测试
  • 【LeetCode】算法详解#8 ---螺旋矩阵
  • Linux->基础IO
  • 佩戴头盔数据集,5498张图片,平均识别率95.3% 其中戴头盔的图有2348张,支持yolo,coco json, pasical voc xml格式的标注
  • Ansible 入门指南:自动化配置管理核心技术与实战 SELinux 配置
  • day051-ansible循环、判断与jinja2模板
  • Frida绕过SSL Pinning (证书绑定)抓包;Frida注入;app无法抓包问题解决。
  • Spring之【写一个简单的IOC容器EasySpring】
  • 2025年亚太杯(中文赛项)数学建模B题【疾病的预测与大数据分析】原创论文分享
  • UE5多人MOBA+GAS 19、创建升龙技能,以及带力的被动,为升龙技能添加冷却和消耗
  • 3. java 堆和 JVM 内存结构
  • YOLOv8
  • pytables模块安装