算法题解记录25+++验证二叉搜索树(百日筑基)

题目描述:

        难度:中等

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

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

  • 节点的左

    子树

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

示例 1:

输入:root = [2,1,3]
输出:true

示例 2:

输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

提示:

  • 树中节点数目范围在[1, 10^4] 内
  • -2^31 <= Node.val <= 2^31 - 1

解题准备:

        1.题意:题目要求验证一棵二叉树,是不是二叉搜索树(BST,即Binary Search Tree),那么我们首先要知道,一棵二叉搜索树是什么样的。

        简单地说,BST有如下性质:第一,其左子树上所有节点的值,都小于根节点值;第二,其右子树上所有节点的值,都大于根节点的值。第三,BST下所有节点,都有BST的性质。

        2.基本操作:就题目看,不涉及增删改,验证必然要涉及查找遍历,姑且认为只有查找和比较。

        3.基础原理:面对树的题目,我们应敏锐地察觉到至少两种方法---BFS广度优先搜索和DFS深度优先搜索。这两种方法几乎是树的算法的基础,大多数算法,都是在二者之上优化而得。

解题思路:

        朴素地说,对于新手,其实一看到这个题目,是不会有什么思路的。

        然而,如果说做过一些题,就能直接得到答案,也非常夸张。

        我在此分享我的错误思路。

        错误思路---左右递归判断

                我最开始的思路比较简单,基于两个基本原理:

                第一,如果一棵树左子节点left的值,大于或等于根节点root的值,说明它不是BST。

                第二,如果一棵树右子节点right的值,小于或等于根节点root的值,说明不是BST。

                这两个原理没有错,却不完全,如果一棵树满足这两个原理,也有可能不是BST,比如下图,7大于5,却满足这个原理,同样,3小于5,也满足这个原理。

                这两个原理没有满足整体,所以我编写的代码在运行之后也报错了,不过,我会在下面提供代码。我先在此说明我的思考过程。【如何将这两个原理转化为代码的】

                第一步,有了原理,尽量往dfs或者bfs方法上靠近。

                第二步,发现判断一个节点是否满足2个原理,只需要判断left与root的关系、right与root的关系即可。【异常处理还没做】

                第三步,得到问题:虽然判断一个节点很简单,怎么判断下一个呢?

                第四步,初始的朴素思想:干脆中序遍历或前序遍历一遍,得到所有节点(存储List),依次进行判断?

                第五步,想到优化思路,既然中序遍历能够遍历每个节点,为什么要遍历一边,然后又从List再遍历一遍?

                第六步,中序原理是左根右,访问操作只在根节点做,那么继续左中右方法,把判断左子放在“左”,判断右子放在“右”,根节点的数据访问忽略了,就可以了。

                第七步,异常:访问到空节点null。

                第八步:if限制,null节点直接返回,又因为要判断子节点与根节点的关系,返回明显不能处理,所以需要额外判断子节点是否为null。

                完成。

        正确思路---中序遍历序列

                这个思路首先要明白一件事:中序遍历,其顺序是左子树、根节点、右子树。

                其中,在左子树left中,其顺序也是left的左子树、left、left的右子树。

                如果一棵树只有一个节点,毫无疑问它是升序的。

                假设这棵树root,它的左子树是left,右子树是right。

                那么,中序遍历时,一定会访问到left的最左子节点X,它是升序的。

                接着,访问最左子节点的父节点F,由于BST性质,最左子X小于F,所以是升序的。

                然后,访问F的右子【也有可能是右子的左子、右子的左子的左子……】P,由于BST性质,XFP升序排列。

                由于这棵树升序排列,那么,它的父树也升序排列,最后,left升序排列,整个节点的中序序列,都升序排列。

                由此,我们只需要得到中序序列,即可判断。

        正确思路---区间逼近

                这个思路是题解的思路,不过与我的错误思路非常接近,它把我的2个原理推进了。

                原理1:左子节点left,一定比root小,左子的左子,一定比root小;左子的右子,一定比root小,并且比左子大……

                原理2:右子节点right,一定比root大,右子的右子,一定比root大;右子的左子,一定比root大,并且比右子小。

                如此,我们可以发现,我的错误思路,就在于判断时,只是把节点与其左右子进行判断,忽略了最重要的根节点。

                然而,问题出现了:如果我们持续用root的值,作为判断依据,如下图:5作为右边所有节点的下限,没有问题,但是9却比7要大,也就是说子树7不符合BST的性质,所以整棵树不是BST。

                换句话说,我们要求上下限是不断变化的,这其实也是二叉树的精髓部分。

                怎么做呢?

                一般的想法是,维护两个变量low、up,使它们代表某个节点的上下限,在每次判断时作为依据。

                不过,如果这两个变量只是代表1个节点上下限,那么我们要开辟一个非常大的空间,用来存储所有的变量对low、up。

                所以,借助递归的方案,我们把维护变量对的操作交给系统,我们只需要递归调用时,传递变量对即可。

解题难点分析:

        无

错误代码---我的思路:

class Solution {public boolean isValidBST(TreeNode root) {boolean flag = true;// 为null不判断if(root.left!=null){if(root.left.val>=root.val){return false;}flag = isValidBST(root.left);}// 看一下是否不是BSTif(!flag){return flag;}// 同理if(root.right!=null){if(root.right.val<=root.val){return false;}flag = isValidBST(root.right);}return flag;}
}

代码---中序遍历:

class Solution {public boolean isValidBST(TreeNode root) {// 存储节点List<Integer> data = new ArrayList<>();fuzhu(root, data);// 依次判断for(int i=0; i<data.size()-1; i++){if(data.get(i) >= data.get(i+1)){return false;}}return true;}private void fuzhu(TreeNode root, List<Integer> data){if(root==null){return;}fuzhu(root.left, data);data.add(root.val);fuzhu(root.right, data);}
}

代码---迭代上下限:

class Solution {public boolean isValidBST(TreeNode root) {return fuzhu(root, Long.MIN_VALUE, Long.MAX_VALUE);}private boolean fuzhu(TreeNode root, long low, long up){// 如果是空节点,即正确 if(root==null){return true;}// 如果超出界限,则错误// 我们可以看出来,每次递归判断,只能判断一个节点,我们不可能一起判断左子和右子if(root.val <= low || root.val >= up){return false;}// 返回左子节点、右子节点的判断。return fuzhu(root.left, low, root.val) && fuzhu(root.right, root.val, up);}
}

以上内容即我想分享的关于力扣热题25的一些知识。

        我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

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

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

相关文章

【MISRA-C-2012】:标准的理解与学习

标准的理解与学习 引用二、Misra-C 规则Misra-C全解读 - Rule 1 标准的C语言环境&#xff08;待更新&#xff09;Misra-C全解读 - Rule 2 未使用的代码&#xff08;待更新&#xff09;Misra-C全解读 - Rule 3 注释&#xff08;待更新&#xff09;Misra-C全解读 - Rule 4 字符与…

如何抠图?6个简单方便的抠图软件教你自己快速抠图

如何抠图&#xff1f;6个简单方便的抠图软件教你自己快速抠图 抠图是图像处理中常见的操作之一&#xff0c;它可以帮助我们从一幅图像中抠出特定的部分&#xff0c;通常用于制作合成图、更换背景或修改图像内容。下面介绍的6款简单方便的抠图软件可以帮助您快速进行抠图操作&a…

PyQt:界面无边框+实现窗口最小化(任务栏图标隐藏+托盘图标显示)

一、整体实现效果 诸如WX、各种管家的桌面显示方式。窗口关闭后&#xff0c;往往是任务栏图标消失&#xff0c;保持右下角托盘图标显示&#xff0c;保持后台运行。双击托盘图标后&#xff0c;窗口显示。 二、代码实现 from PyQt5.QtWidgets import * from ato_upgrade impo…

CSS常用滤镜效果

CSS 提供了多种滤镜效果&#xff0c;可以通过 filter 属性应用于 HTML 元素。以下是一些常用的 CSS 滤镜效果&#xff1a; 一、灰度 (Grayscale) 将图像转换为灰度图像。值在 0%&#xff08;原始图像&#xff09;和 100%&#xff08;完全灰度&#xff09;之间。 filter: gra…

【回溯 栈 代数系统 动态规划】282. 给表达式添加运算符

本文涉及知识点 回溯 栈 代数系统 动态规划 LeetCode 282. 给表达式添加运算符 给定一个仅包含数字 0-9 的字符串 num 和一个目标值整数 target &#xff0c;在 num 的数字之间添加 二元 运算符&#xff08;不是一元&#xff09;、- 或 * &#xff0c;返回 所有 能够得到 ta…

Ngnix VTS模块添加和测试

目录 VTS模块介绍 上传软件包xftp/lrzsz 执行脚本 添加vts的配置 测试 测试&#xff1a;nginx.conf配置文件是否有语法错误 测试&#xff1a;windows机器上访问效果 VTS模块介绍 Nginx VTS模块&#xff08;nginx Virtual Host Traffic Status Module&#xff09;是一个第三…

【C++初阶】string模拟实现

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

【精读Yamamoto】方向性连接如何丰富神经网络的功能复杂度 | 体外神经元培养实验 | 脉冲神经元模型(SNN) | 状态转移模型

探索大脑的微观世界&#xff1a;方向性连接如何丰富神经网络的功能复杂度 在神经科学领域&#xff0c;理解大脑如何通过其复杂的网络结构实现高级功能一直是一个核心议题。最近&#xff0c;一项由Nobuaki Monma和Hideaki Yamamoto博士领导的研究为我们提供了新的视角&#xff…

cuttag学习笔记

由于课题可能用上cut&tag这个技术&#xff0c;遂跟教程学习一波&#xff0c;记录一下以便后续的学习&#xff08;主要是怕忘了&#xff09; 教程网址cut&tag教程 背景知识&#xff1a;靶标下裂解与标记&#xff08;Cleavage Under Targets & Tagmentation&#xf…

90后医生下班摆摊就能赚1500?看内行人是如何分析的?2024普通人逆袭的机会,2024普通人想翻身的风口行业

“在自己空余的时间&#xff0c;做点自己喜欢的事情”这就是浙江义乌的王医生&#xff0c;摆摊被采访时的回答。王大夫说&#xff0c;自己兼职已经有半年多了&#xff0c;每天的营业额能达到1500元。同时王医生表示&#xff0c;自己的目标是开一间自己的小店。 看到这里&#x…

新版Idea配置仓库教程

这里模拟的是自己搭建的本地仓库环境&#xff0c;基于虚拟机搭建利用gogs创建的仓库 1、Git环境 你需要准备好git和仓库可以使用github 、gitee等 1.1 拉取代码 本项目使用 Git 进行版本控制&#xff0c;在 gogs 上创建一个个人使用的 git 仓库&#xff1a; http://192.168.…

1.5.2 基于XML配置方式使用Spring MVC

用户登录演示效果 实战概述&#xff0c;可以帮助你更好地理解整个流程。 项目创建 创建了一个名为 SpringMvcDemo01 的 Jakarta EE 项目。通过 Maven 添加了项目所需的依赖&#xff0c;包括 Spring MVC、JSTL 等。 视图层页面 创建了登录页面&#xff08;login.jsp&#xff0…

计算机毕业设计springboot体育馆场地预约管理系统【附源码】

计算机毕业设计springboot体育馆场地预约管理系统[附源码] &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制…

良心实用的电脑桌面便利贴,好用的便利贴便签小工具

在日常办公中&#xff0c;上班族经常需要记录临时任务、重要提醒或者突发的灵感。比如&#xff0c;在紧张的项目会议中&#xff0c;忽然想到一个改进的点子&#xff0c;或者是在处理邮件时&#xff0c;需要记下对某个客户的回复要点。在这些场景下&#xff0c;如果能直接在电脑…

基于SpringBoot+Vue的物流管理系统

运行截图 获取方式 Gitee仓库

Gitee添加仓库成员

1.进入你的项目 2.点击管理 3.左侧有个仓库管理 4.要加哪个加哪个&#xff0c;有三个方式~ 可以直接添加之前仓库合作过的开发者

In Context Learning(ICL)个人记录

In Context Learning&#xff08;ICL&#xff09;简介 In Context Learning&#xff08;ICL&#xff09;的关键思想是从类比中学习。上图给出了一个描述语言模型如何使用 ICL 进行决策的例子。首先&#xff0c;ICL 需要一些示例来形成一个演示上下文。这些示例通常是用自然语言…

react18【实战】tab切换,纯前端列表排序(含 lodash 和 classnames 的安装和使用)

技术要点 动态样式 className{tabItem ${currentType item.value && "active"}}安装 lodash npm i --save lodash使用 lodash 对对象数组排序&#xff08;不会改变源数组&#xff09; _.orderBy(dataList, "readNum", "desc")src\De…

ArcGIS10.2系列许可到期解决方案

本文手机码字&#xff0c;不排版了。 昨晚&#xff08;2021\12\17&#xff09;12点后&#xff0c;收到很多学员反馈 ArcGIS10.2系列软件突然崩溃。更有的&#xff0c;今天全单位崩溃。 ​ 提示许可15天内到期。之前大部分许可是到2021年1月1日的。 ​ 后续的版本许可都是永久的…

深度学习技术之加宽前馈全连接神经网络

深度学习技术 加宽前馈全连接神经网络1. Functional API 搭建神经网络模型1.1 利用Functional API编写宽深神经网络模型进行手写数字识别1.1.1 导入需要的库1.1.2 加载虹膜&#xff08;Iris&#xff09;数据集1.1.3 分割训练集和测试集1.1.4 定义模型输入层1.1.5 添加隐藏层1.1…