数据结构与算法——Java实现 52.力扣98题——验证二叉搜索树

news2024/11/8 2:01:50

我将一直向前,带着你给我的淤青

                                        —— 24.11.5

98. 验证二叉搜索树

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

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

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

示例 1:

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

示例 2:

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

方法1 递归求解

思路

提前设置一个prev对象,首先设置为最小值,从根节点开始,对每个节点进行递归,左—值—右中序遍历,不断更新节点值与prev存储的上一个节点的值,直到找到了不符合二叉树的定义的子树,返回false,若将二叉树全部遍历完成,则判断符合二叉搜索树的规则,返回true


不足

无论在哪个节点提前判断到二叉树不合法,不会停止递归,而会继续递归判断不合法树的子树,会产生一些多余的比较


/**
 * 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 {
    long prev = Long.MIN_VALUE;

    
    public boolean isValidBST(TreeNode node){
        if (node == null){
            return true;
        }
        // 中序遍历:左 - 根 - 右
        boolean a = isValidBST(node.left);

        if(prev >= node.val){
            return false;
        }else{
            prev = node.val;
        }

        boolean b = isValidBST(node.right);
        return a && b;
    }
}


方法2 中序遍历+双指针+栈

Stack 是一种遵循后进先出(Last-In-First-Out,LIFO)原则的数据结构

特性

1.后进先出(LIFO - Last In First Out)原则:最后进入栈的元素最先被取出。就像往一个桶里叠盘子,最后放进去的盘子会最先被拿出来。

2.操作受限:主要操作是压入(push)元素和弹出(pop)元素,以及查看栈顶元素(peek)和判断栈是否为空(empty)。

3.高效的插入和删除:在栈顶进行插入和删除操作的时间复杂度通常为 O (1) ,这些操作不需要移动大量元素。

常用方法

push(E item) :将元素压入栈顶
pop() :弹出并返回栈顶元素
peek() :查看栈顶元素,但不弹出
empty() :判断栈是否为空


思路

将所有的子节点全部压入栈中,当遍历到最左边的节点时,开始弹栈,在弹栈的过程中,不断比较弹出值与右边节点的大小,由于二叉树的特性:左子树 < 根结点 < 右子树以及栈的特性:先进先出FIFO,每弹出一个节点时,进行比较,如果发现有不符合二叉树规则的节点,则返回false


算法全流程:

① 初始化:

`TreeNode p = node;`:设置当前节点 'p' 为根节点。

LinkedList<TreeNode> stack = new LinkedList<>();‘:创建一个栈用于存储节点。

'long prev = Long.MIN_VALUE;':初始化 `prev` 为' Long.MIN_VALUE

② 中序遍历:

使用来模拟递归调用,首先将所有左子节点压入栈中。

当到达最左边的叶子节点时,开始弹栈并处理节点值

每次弹出一个节点时,检查其值是否大于'prev',如果不大于,则更新 'prev` 为当前节点的值,并将 'p` 指向当前节点的右子节点,继续遍历。如果大于,则判断为不合法,返回 ‘False’

③ 结束条件

如果遍历完所有节点且没有发现违反BST性质的情况,返回 ‘True'

注:为保证确定最小值,使用Long类型的最小值MIN_VALUE


/**
 * 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 {
    public boolean isValidBST(TreeNode node) {
        TreeNode p = node;
        LinkedList<TreeNode> stack = new LinkedList<>();
        long prev = Long.MIN_VALUE; // 代表上一个值
        while (p != null || !stack.isEmpty()) {
            if (p != null) {
                // push 压栈
                stack.push(p);
                p = p.left;
            } else {
                // pop 弹栈
                TreeNode pop = stack.pop();
                // 处理值
                if (prev >= pop.val){
                    return false;
                }
                prev = pop.val;
                p = pop.right;
            }
        }
        return true;
    }
}


方法3 判断合法 — 上下界(剪枝操作

思路

对于每一个节点来说,其左边的祖先节点key值都要比原节点小,其右边的节点key值都要比原节点大,如果对于每个节点都符合要求,则返回true,否则返回false


/**
 * 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 {
    public boolean isValidBST(TreeNode node){
        return doValid(node,Long.MIN_VALUE,Long.MAX_VALUE);
    }

    private boolean doValid(TreeNode node,long min,long max){
        if (node == null){
            return true;
        }

        if (node.val <= min || node.val >= max){
            return false;
        }
        return doValid(node.left,min,node.val) && doValid(node.right, node.val, max);
    }
}

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

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

相关文章

[mysql]DDL,DML综合案例,

综合案例 题目如下 目录 综合案例 ​编辑 ​编辑 # 1、创#1建数据库test01_library # 2、创建表 books&#xff0c;表结构如下&#xff1a; # 3、向books表中插入记录库存 # 4、将小说类型(novel)的书的价格都增加5。 # 5、将名称为EmmaT的书的价格改为40&#xff0c;并将…

书生实战营第四期-基础岛第三关-浦语提示词工程实践

一、基础任务 任务要求&#xff1a;利用对提示词的精确设计&#xff0c;引导语言模型正确回答出“strawberry”中有几个字母“r”。 1.提示词设计 你是字符计数专家&#xff0c;能够准确回答关于文本中特定字符数量的问题。 - 技能&#xff1a; - &#x1f4ca; 分析文本&…

国药准字生发产品有哪些?这几款不错

头秃不知道怎么选的朋友们看这&#xff0c;基本上市面上火的育发精华我都用了个遍了&#xff0c;陆陆续续也花了有大几w了&#xff0c;都是真金白银总结出来的&#xff0c;所以必须要给掉发人分享一些真正好用的育发产品&#xff0c;大家可以根据自己实际情况来选择。 1. 露卡菲…

构建基于 DCGM-Exporter, Node exporter,PROMETHEUS 和 GRAFANA 构建算力监控系统

目录 引言工具作用概述DCGM-ExporterNode exporterPROMETHEUSGRAFANA小结 部署单容器DCGM-ExporterNode exporterPROMETHEUSGRAFANANode exporterDCGM-Exporter 多容器Node exporterDCGM-ExporterDocker Compose 参考 引言 本文的是适用对象&#xff0c;是希望通过完全基于Doc…

Java入门14——动态绑定(含多态)

大家好&#xff0c;我们今天来学动态绑定和多态&#xff0c;话不多说&#xff0c;开始正题~ 但是要学动态绑定之前&#xff0c;我们要学习一下向上转型&#xff0c;方便后续更好地理解~ 一、向上转型 1.什么是向上转型 网上概念有很多&#xff0c;但其实通俗来讲&#xff0c…

Request 和 Response 万字详解

文章目录 1.Request和Response的概述2.Request对象2.1 Request 继承体系2.2 Request获取请求数据2.2.1 获取请求行数据2.2.2 获取请求头数据2.2.3 获取请求体数据2.2.4 获取请求参数的通用方式 2.3 解决post请求乱码问题 掌握内容讲解内容小结 2.4 Request请求转发 3.HTTP响应详…

Qt QCustomplot 在采集信号领域的应用

文章目录 一、常用的几种开源库:1、QCustomPlot:2、QChart:3、Qwt:QCustomplot 在采集信号领域的应用1、应用实例时域分析频谱分析2.数据筛选和处理其他参考自然界中的物理过程、传感器和传感器网络、电路和电子设备、通信系统等都是模拟信号的来源。通过可视化模拟信号,可以…

【初阶数据结构与算法】沉浸式刷题之顺序表练习(顺序表以及双指针两种方法)

文章目录 顺序表练习1.移除数组中指定的元素方法1&#xff08;顺序表&#xff09;方法2&#xff08;双指针&#xff09; 2.删除有序数组中的重复项方法1&#xff08;顺序表&#xff09;方法2&#xff08;双指针&#xff09; 3.双指针练习之合并两个有序数组方法1&#xff08;直…

机器学习—矩阵乘法

矩阵只是一个或两个数组。 如何在向量之间取点积&#xff1f; 让我们用列向量[1,2]*[[3,4]&#xff0c;如果z是这两个向量之间的点积&#xff0c;然后通过乘以第一个元素来计算z&#xff0c;通过这里的第一个元素&#xff0c;所以是1*3加第二个元素乘以第二个元素即2*4&#…

使用 ADB 在某个特定时间点点击 Android 设备上的某个按钮

前提条件 安装 ADB&#xff1a;确保你已经在计算机上安装了 Android SDK&#xff08;或单独的 ADB&#xff09;。并将其添加到系统环境变量中&#xff0c;以便你可以在命令行中运行 adb。 USB调试&#xff1a;确保 Android 设备已启用 USB 调试模式。这可以在设备的“设置” -…

数据结构之二叉树前序,中序,后序习题分析(递归图)

1.比较相同的树 二叉树不能轻易用断言&#xff0c;因为树一定有空 2.找结点值 3.单值二叉树 4.对称二叉树 5.前序遍历

[CUDA] 将已有的地址空间设置为pinned memory

文章目录 1. cudaHostRegitster的使用构建pinned memory1.1 基本使用1.2 cudaHostRegister 需要设置cudaSetDevice? Reference 1. cudaHostRegitster的使用构建pinned memory 注意使用C申请的内存空间&#xff0c;在进行copy是无法实现流的最大异步性&#xff1b;因此使用cud…

各种数据库介绍

1. 关系型数据库&#xff08;RDBMS&#xff09; MySQL • 特点&#xff1a;开源、免费&#xff0c;社区版功能强大且稳定。支持大量的并发连接&#xff0c;常用于Web应用。 • 适用场景&#xff1a;中小型网站、博客、电商等。 PostgreSQL • 特点&#xff1a;功能丰富&#xf…

ONLYOFFICE 8.2版本评测:超好用办公工具

前言 在技术的快速发展和工作方式的持续演进下&#xff0c;现代办公软件正变得越来越强大和多样化。ONLYOFFICE&#xff0c;作为市场上备受瞩目的一体化办公解决方案&#xff0c;以其全面的文档编辑、表格处理和演示制作功能&#xff0c;满足了用户在不同办公场景下的需求。最…

Python基础学习_01

目录 1、注释 2、数字和数学计算 3、变量 4、字符串 5、打印 6、本节总结 1、注释 • 什么是注释&#xff1f; 1&#xff09;注释就是用自然语言向代码阅读者说明代码的功能和意义 • 注释 1&#xff09;单行注释使用 # 为开头&#xff1b;并且不能换行…

不容错过的电脑监控软件TOP10|电脑屏幕监控软件推荐(收藏)

随着企业对员工管理和数据安全的要求日益提高&#xff0c;电脑监控软件已经成为许多公司确保工作效率、信息保密以及员工行为合规性的重要工具。无论是需要跟踪员工的工作进度&#xff0c;还是防止数据泄露和滥用&#xff0c;选择合适的监控软件至关重要。今天我们为你整理了十…

Python练习10

Python日常练习 题目&#xff1a; 编写程序&#xff0c;输出如下所示图案。 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 要求&#xff1a; 使用for循环的方式完成 --------------------------------------------------------- 注意&#xff1a; …

【DM系列】DM 集成 JDBC 开发指南

前言 数据库访问是数据库应用系统中非常重要的组成部分&#xff0c;DM 作为一个通用数据库管理系统&#xff0c;提供了多种数据库访问接口&#xff0c;包括 ODBC、JDBC、DPI 等方式。本开发指南详细介绍了 DM 的各种访问接口、相应开发环境的配置、以及一些开发用例。本指南的主…

长亭那个检测能力超强的 WAF,出免费版啦

告诉你们一个震撼人心的消息&#xff0c;那个检测能力超强的 WAF——长亭雷池&#xff0c;他推出免费社区版啦&#xff0c;体验地址见文末。 八年前我刚从学校毕业&#xff0c;在腾讯做安全研究&#xff0c;看到宇森在 BlackHat 上演讲的议题 《永别了&#xff0c;SQL 注入》 …

Excel 无法打开文件

Excel 无法打开文件 ‘新建 Microsoft Excel 工作表.xlsx",因为 文件格式或文件扩展名无效。请确定文件未损坏&#xff0c;并且文件扩展名与文件的格式匹配。