题目描述

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

节点的左子树只包含 严格小于 当前节点的数。
节点的右子树只包含 严格大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

示例 1:
在这里插入图片描述
输入:root = [2,1,3]
输出:true

示例 2:
在这里插入图片描述
输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

提示:
树中节点数目范围在[1,104][1, 10^4][1,104]
−231<=Node.val<=231−1-2^31 <= Node.val <= 2^31 - 1231<=Node.val<=2311

思考一:前序遍历(递归检测值范围)

二叉搜索树的根节点的值大于所有左子树的节点,小于所有右子树的节点。写递归函数时很容易把节点值的范围搞错,如下图不是二叉搜索树:
在这里插入图片描述
节点41 小于祖先节点42,不满足二叉搜索树根节点右子树所有节点大于根节点值条件。
因此要定义一个递归函数,设置上下限参数,检测左子树时才更新上限值,检测右子树时才更新下限值。
核心是为每个节点设定合法值区间:根节点的合法区间为 (-∞, +∞),左子节点的区间上限更新为父节点值(需严格小于父节点),右子节点的区间下限更新为父节点值(需严格大于父节点),递归验证所有节点是否在合法区间内。

算法过程

  1. 初始化递归:调用辅助函数 check,传入根节点及初始区间 (-Infinity, Infinity)(根节点无上下限约束)。
  2. 递归终止条件:若当前节点为 null(空树/空子树),符合BST规则,返回 true
  3. 节点值合法性检测
    • 若当前节点值 <= 区间下限>= 区间上限(违反“左小右大”规则),返回 false
  4. 递归验证子树
    • 验证左子树:左子树的合法区间为 (原下限, 当前节点值)(左子树需严格小于当前节点);
    • 验证右子树:右子树的合法区间为 (当前节点值, 原上限)(右子树需严格大于当前节点);
    • 只有左右子树均验证通过,才返回 true
  5. 返回结果:递归回溯后,返回最终验证结果。

时空复杂度

  • 时间复杂度:O(n),n为二叉树节点总数。
    原因:每个节点仅被验证1次,递归操作无重复遍历,总操作次数与节点数线性相关。
  • 空间复杂度:O(h),h为二叉树高度。
    原因:递归调用栈深度取决于树高,平衡树h=O(log n),链状树h=O(n)。

代码(前序遍历版)

/*** Definition for a binary tree node.* function TreeNode(val, left, right) {*     this.val = (val===undefined ? 0 : val)*     this.left = (left===undefined ? null : left)*     this.right = (right===undefined ? null : right)* }*/
/*** @param {TreeNode} root* @return {boolean}*/
var isValidBST = function(root) {// 初始区间:根节点无上下限,用正负无穷表示return check(root, -Infinity, Infinity);
};// 辅助函数:验证节点是否在 [low, high) 区间内(左闭右开,保证严格大小)
function check(node, low, high) {// 空节点符合BST规则if (!node) return true;// 节点值超出合法区间,不是BSTif (node.val <= low || node.val >= high) {return false;}// 左子树区间更新为 [low, node.val),右子树更新为 [node.val, high)return check(node.left, low, node.val) && check(node.right, node.val, high);
}

思考二:中序遍历(验证序列严格递增)

核心是利用BST的中序遍历特性:BST的中序遍历结果是严格递增的序列(左→根→右,值依次增大)。通过中序遍历收集节点值,再检查序列是否严格递增,即可验证是否为有效BST。

算法过程

  1. 中序遍历收集节点值
    • 初始化空数组 arr,用于存储中序遍历的节点值;
    • 递归执行中序遍历:先遍历左子树,再将当前节点值加入 arr,最后遍历右子树(左→根→右)。
  2. 验证序列严格递增
    • 遍历数组 arr,若存在任意 i 满足 arr[i] >= arr[i+1](非严格递增),返回 false
    • 若所有相邻元素均满足 arr[i] < arr[i+1],返回 true
  3. 返回结果:返回序列验证结果。

时空复杂度

  • 时间复杂度:O(n),n为二叉树节点总数。
    原因:中序遍历收集节点值需O(n),遍历数组验证需O(n),总时间为O(n)。
  • 空间复杂度:O(n)(含存储数组)。
    原因:数组 arr 需存储所有节点值(O(n)),递归调用栈需O(h),总空间由数组主导,为O(n)。
    (优化:可不用数组,用变量记录前一个节点值,空间复杂度降至O(h),见下方补充)

代码(中序遍历版,基础版)

/*** Definition for a binary tree node.* function TreeNode(val, left, right) {*     this.val = (val===undefined ? 0 : val)*     this.left = (left===undefined ? null : left)*     this.right = (right===undefined ? null : right)* }*/
/*** @param {TreeNode} root* @return {boolean}*/
var isValidBST = function(root) {const arr = [];// 中序遍历收集节点值inOrder(root, arr);// 验证序列是否严格递增for (let i = 0; i < arr.length - 1; i++) {if (arr[i] >= arr[i + 1]) return false;}    return true;
};// 中序遍历:左→根→右
function inOrder(node, arr) {if (!node) return;inOrder(node.left, arr);arr.push(node.val);inOrder(node.right, arr);
}
中序遍历优化版(无数组,O(h)空间)
var isValidBST = function(root) {let prev = -Infinity; // 记录前一个节点值,初始为负无穷let isValid = true;   // 标记是否为有效BSTfunction inOrder(node) {if (!node || !isValid) return; // 提前终止(已判定无效)inOrder(node.left);            // 左// 验证当前节点值是否大于前一个节点值if (node.val <= prev) {isValid = false;return;}prev = node.val;               // 更新前一个节点值(根)inOrder(node.right);           // 右}inOrder(root);return isValid;
};

两种方法对比

方法核心逻辑时间复杂度空间复杂度(基础版)优势
前序遍历(值范围)递归验证节点合法区间O(n)O(h)无额外存储,空间更优
中序遍历(有序性)验证中序序列严格递增O(n)O(n)(数组)逻辑直观,易理解
中序遍历(优化版)实时对比前节点值O(n)O(h)兼顾直观与空间效率

适用场景

  • 若追求空间效率,优先选择“前序遍历(值范围)”或“中序遍历优化版”;
  • 若追求代码简洁直观,可选择“中序遍历(数组版)”(节点数较少时无明显性能问题)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/96049.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/96049.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/96049.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Apache Tomcat 教程:从入门到精通(含目录结构与版本详解)

​​​​​​1. 背景​​ Apache Tomcat 是一个开源的 ​​Java Servlet 容器​​&#xff0c;由 ​​Apache 软件基金会&#xff08;ASF&#xff09;​​ 开发和维护&#xff0c;最初由 ​​Sun Microsystems​​ 的软件架构师 ​​James Duncan Davidson​​ 设计&#xff0…

设计模式从入门到精通之(六)策略模式

策略模式&#xff1a;让算法灵活切换的秘密武器在日常开发中&#xff0c;算法的选择常常是程序设计的核心&#xff0c;比如支付方式的选择、排序逻辑的切换、促销活动的动态调整等。当需求变化时&#xff0c;我们需要在多个算法之间切换&#xff0c;但又不希望修改已有代码。如…

安装MATLAB205软件记录

安装MATLAB2025 一台电脑可以安装多个版本的MATLAB; 下载资源 微信公众平台-MATLAB R2025a v25.1下载及安装教程 安装步骤 解压, 压缩文件大小为13.8GB 装载 选中setup.exe右键单击以管理员身份运行 我有文件安装密钥 接受许可条款 复制粘贴密钥 63733-59078-50866-02827-…

MySQL 基础架构(一):SQL语句的执行之旅

MySQL系列文章 MySQL 基础架构&#xff08;一&#xff09;&#xff1a;SQL语句的执行之旅 你是否好奇过&#xff0c;一条看似简单的SQL查询语句&#xff0c;在MySQL内部究竟经历了怎样的"奇幻之旅"&#xff1f;从连接建立到结果返回&#xff0c;MySQL是如何层层处理、…

Spring Boot 使用 Druid 连接池极致优化

在 Spring Boot 中使用 Druid 连接池进行极致优化&#xff0c;需要从核心参数调优、监控体系搭建、安全增强、连接管理及性能适配等多个维度综合考虑。以下是分阶段的详细优化策略&#xff1a;一、基础环境准备确保使用最新稳定版 Druid&#xff08;截至 2024 年推荐 1.2.38&am…

【Big Data】Apache Kafka 分布式流处理平台的实时处理实践与洞察

目录 一、Apache Kafka是什么 二、Kafka的诞生背景 三、Kafka的架构设计 四、Kafka解决的技术问题 五、Kafka的关键特性 六、Kafka与其他消息队列系统的对比 七、Kafka的工作原理 八、Kafka的部署与使用方法 1. 集群部署 2. 生产者与消费者配置 3. 安全配置 4. 监控…

23种设计模式——装饰器模式(Decorator Pattern)详解

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a;设计模式 ✨特色专栏&#xff1a;知识分享 &#x…

《sklearn机器学习——聚类性能指标》Davies-Bouldin Index (戴维斯-博尔丁指数)

Davies-Bouldin Index (戴维斯-博尔丁指数)简介 概念与定义 Davies-Bouldin Index是由David L. Davies和Donald W. Bouldin于1979年提出的一种用于评估聚类算法效果的内部指标。它通过计算每个簇内数据点之间的相似性和不同簇中心点的距离来衡量聚类结果的质量。DBI的值越低&am…

QT的学习(一)

前言&#xff1a;距离上一次摸QT已经快10年了&#xff0c;时光匆匆&#xff0c;现在已经到6.9版本了 一、安装QT 1.1、下载链接 https://mirrors.tuna.tsinghua.edu.cn/qt/official_releases/online_installers/ 这是国内镜像&#xff0c;比官网快很多了&#xff0c;官网那个…

亚洲数字能源独角兽的 “安全密码”:Parasoft为星星充电筑牢软件防线

当你在充电桩前等待爱车满电时&#xff0c;是否想过&#xff1a;这看似简单的充电过程&#xff0c;背后藏着多少软件代码的精密协作&#xff1f;作为亚洲数字能源领域的头部企业&#xff0c;星星充电用 “移动能源网” 连接着千万用户与新能源世界&#xff0c;而支撑这一切的&a…

安装Codex(需要用npm)

查看已经安装的包 npm list -g --depth0 npm uninstall -g anthropic-ai/claude-code 如果要卸载什么东西 安装Codex &#xff1a;npm i -g openai/codex https://openai.com/zh-Hant/codex/ 之后登录gpt账号&#xff0c;完成后就是下面的样子

HarmonyOS 开发学习分享:从入门到认证的完整路径

HarmonyOS 开发学习分享&#xff1a;从入门到认证的完整路径 大家好&#xff01;我是赵老师&#xff0c;一个深耕鸿蒙生态的开发者。最近刚通过鸿蒙生态赋能资源丰富度建设活动的讲师认证&#xff0c;想和大家分享一下 HarmonyOS 开发的学习心得和认证经验。 我的鸿蒙开发经历作…

使用Spring Boot DevTools快速重启功能

背景 在Spring Boot项目中&#xff0c;修改一些简单的代码后&#xff0c;每次手动终止并启动整个项目比较繁琐且消耗时间。Spring Boot DevTools 提供了开发时的热重启功能&#xff0c;使得在开发过程中修改代码后可以快速生效&#xff0c;而无需手动重启整个应用&#xff0c;可…

7.4Element Plus 分页与表格组件

el-pagination el-table 这两个组件是后台管理系统中最常用的数据展示与交互组合&#xff0c;通常配合使用实现 分页加载、排序、筛选、操作 等功能。一、分页组件 el-pagination用于控制大量数据的分页展示。✅ 基本结构<el-paginationv-model:current-page"currentPa…

搭建机器学习模型的数据管道架构方案

本篇文章Designing Data Pipeline Architectures for Machine Learning Models适合对数据管道架构感兴趣的读者&#xff0c;亮点在于详细解析了传统数据仓库、云原生数据湖和现代湖仓这三种架构&#xff0c;帮助理解如何将原始数据转化为可操作的预测。文中还强调了不同架构的优…

GitHub 热榜项目 - 日榜(2025-09-06)

GitHub 热榜项目 - 日榜(2025-09-06) 生成于&#xff1a;2025-09-06 统计摘要 共发现热门项目&#xff1a;15 个 榜单类型&#xff1a;日榜 本期热点趋势总结 本期GitHub热榜显示AI自动化与安全运维为核心趋势。Bytebot、EvolutionAPI等AI代理项目凸显自然语言交互和容器化…

Homebrew执行brew install出现错误(homebrew-bottles)

问题描述 在使用homebrew安装软件时&#xff0c;出现如下报错&#xff1a; Downloading https://mirrors.aliyun.com/homebrew/homebrew-bottles/bottles-portable-ruby/portable ruby-3.4.5.arm64_big_sur.bottle.tar.gz curl: (22) The requested URL returned error: 404 …

23种设计模式——工厂方法模式(Factory Method Pattern)详解

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a;设计模式 ✨特色专栏&#xff1a;知识分享 &#x…

NPU边缘推理识物系统

目录 NPU边缘推理识物系统 一、项目简介 二、硬件介绍 三、软件设计 1、底层NPU推理代码 2、应用层QT显示代码 四、项目成果展示 NPU边缘推理识物系统 一、项目简介 物品分类是计算机视觉的重要技术&#xff0c;本项目的核心是&#xff1a;使用NPU&#xff08;神经网络…

C# WinForm分页控件实现与使用详解

C# WinForm分页控件实现与使用详解概述在WinForms应用程序开发中&#xff0c;数据分页是常见的需求。本文将介绍如何实现一个功能完整的分页控件&#xff0c;并在窗体中如何使用该控件进行数据分页展示。分页控件实现核心属性与字段public partial class PageControl : UserCon…