二叉搜索树的后序遍历序列

二叉搜索树的后序遍历序列

  • 背景
  • 题目描述
  • 题解

背景

每次重复刷到这题都没有思路,看答案也总需要理解一会,但是下次又忘了,哈哈哈,因此记录一下思路.

题目描述

牛客地址:

https://www.nowcoder.com/practice/a861533d45854474ac791d90e447bafd

描述
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回 true ,否则返回 false 。假设输入的数组的任意两个数字都互不相同。

数据范围:
节点数量 0≤n≤1000 ,节点上的值满足 1≤val≤105,保证节点上的值各不相同
要求:
空间复杂度 O(n) ,时间时间复杂度 O(n2)
提示:
1.二叉搜索树是指父亲节点大于左子树中的全部节点,但是小于右子树中的全部节点的树。
2.该题我们约定空树不是二叉搜索树
3.后序遍历是指按照 “左子树-右子树-根节点” 的顺序遍历
4.参考下面的二叉搜索树,
示例 1
在这里插入图片描述
示例1
输入:[1,3,2]
返回值:true
说明:是上图的后序遍历 ,返回true
示例2
输入:[3,1,2]
返回值:false
说明:
不属于上图的后序遍历,从另外的二叉搜索树也不能后序遍历出该序列 ,因为最后的2一定是根节点,前面一定是孩子节点,可能是左孩子,右孩子,根节点,也可能是全左孩子,根节点,也可能是全右孩子,根节点,但是[3,1,2]的组合都不能满足这些情况,故返回false
示例3
输入:[5,7,6,9,11,10,8]
返回值:true

题解

思路:
首先根据题意我们需要需要想到两点:
第一点:题干给的是后序遍历的排序数组,二叉树的后序遍历顺序 是 左结点-右结点-根结点,因此,最后一个结点一定是根结点,这点很重要.
第二点:题干给的是二叉搜索树,二叉搜索树的特点是,根结点的左子树的所有结点一定比根结点小,根结点的右子树的所有结点一定根结点大.

通过这两个特点,然后来分析给出的后序遍历数组,如果我们能想到,利用某种方式来验证二叉树的左子树一定比根结点小,二叉树的右子树一定比根结点大.那么这个数组就符合要求,反之则不符合.

通过这个思路,我们首先肯定需要找到根结点,然后才能进行左右子树的判断.因为是后序遍历,所以数组的最后一位肯定是根结点.根结点找到了,我们还需要找到左右子树,找到左右子树后,我们再对左右子树进行验证即可.下面讨论两种寻找左右子树的方法.

我们先举个例子,比如给出树 [1,3,2,5,4]
在这里插入图片描述
那么数组的最后一位,也就是4是树的根结点,接下来我们验证左子树[1,3,2]和右子树[5]是否满足要求即可.但是到这里还没结束,我们还需要对2这个左子树的子结点进行验证.如果子结点后面还有子结点,我们可能还需要继续进行验证.由此我们可能有了一种思路,递归.

方法一:递归
我们首先根据最后一位4,可以把前面的[1,3,2,5]分成两组,比4小的左子树[1,3,2],比4大的右子树[5],接着再进行验证左子树的元素是否都比4小,右子树的元素是否都比4大.如果有不满足的,则验证失败.

验证完后,我们还需要对两个子树进行递归验证,右子树[5]已经没有子树了,因此满足,要求,左子树[1,3,2]又可以以根结点2来进行划分,且它的左子树为[1],右子树为[3].划分完后继续验证,很明显都满都要求.接下来我们上代码:

import java.util.*;
public class Solution {public boolean VerifySquenceOfBST(int[] sequence) {if (sequence.length == 0) return false;return order(sequence, 0, sequence.length - 1);}public boolean order(int[] sequence, int start, int end) {// 剩一个节点的时候 返回 trueif (start >= end) return true;int j;//根结点一定在最后一个int root = sequence[end];//且左子树一定在剩下结点的左半部分,右子树一定在剩下结点的右半部分// 从后往前找到左子树和右子树的分界点,找到比root小的第一个即为分界点for (j = end; j >= start; j--) {int cur = sequence[j];//当找到小于根的时候表明找到了分界点了if (cur < root) break;}//找到分界点后,从分界点开始,判断所谓的左子树中是否有不合法(不符合二叉搜索树)的元素//这里只需要验证左子树,因为我们是从后往前找比root小的,如果右子树存在比root小的,那么//我们找的分界点会出错,也会导致最终验证不通过.for (int i = j; i >= start; i--) {int cur = sequence[i];if (cur > root) return false;}return order(sequence, start, j) && order(sequence, j + 1, end - 1);}
}

算法中有一点需要我们格外注意的,就是每次递归方法中我们只验证了左子树,没有验证右子树.这是为什么呢?
因为我们是从后往前找比root小的分界点,如果右子树存在比root小的,那么我们找的分界点会出错,也会导致最终验证不通过.

时间复杂度:𝑂(𝑛2),递归操作每次排除掉一个根节点,因此递归次数是O(n),而最差情况下树退化成链表,每次递归内又要遍历所有节点,还是O(n),因此最终代价就是O(n2)
空间复杂度:O(n),最差情况下树退化成链表,递归深度就是O(n)

方法二:逆向后序遍历+单调栈
相比于上面一种解法,这种解效率更高,但是理解更困难.
我们都知道,从后往前遍历,即顺序变成了根->右子树->左子树。
由于右子树>根>左子树,所以遍历序列过程有下降时,说明当前已经来到了左子树,利用单调栈找到大于当前值的最小值,该值即为局部树中的根节点。
初始时,令根节点root无穷大,则当前树为该根节点的左子树。遍历过程中,逐步缩小root的值,因为所有的操作(主要就是对结点是否合规的判断)都是在当前根节点root的左子树中进行的,所以保证遍历的值小于root即可满足判断条件,否则为false;
代码入下:

import java.util.Stack;
public class Solution {public boolean VerifySquenceOfBST(int [] sequence) {// 处理序列为空情况if(sequence.length == 0) return false;//首先定义根结点为最大值,这说数组组成的树是root的左子树.int root = Integer.MAX_VALUE;Stack<Integer> stack = new Stack<>();// 以根,右子树,左子树顺序遍历for(int i= sequence.length-1;i>=0;i--){//这里判断的sequence[i]一定是左子结点,因为如果是右子结点就不会去更新root,由下面的stack.peek()>sequence[i]保证.//且一开始数组组成的树它就是左子树,因此可以直接判断.//所以确定根后一定是在右子树节点都遍历完了,因此当前sequence未遍历的节点中只含左子树,左子树的节点如果>root则说明违背二叉搜索的性.//这里不用判断整个左子树,如果是左子树的左子树,后面会利用单调栈来重新确定root,然后再循环判断.if(sequence[i]>root) return false;// 进入左子树的契机就是sequence[i]的值小于前一项的时候,这时可以确定root//且会循环的出栈取root,直到找到比root还小的值停止,那么上一个值一定是sequence[i]的直接根结点while(!stack.isEmpty() && stack.peek()>sequence[i]){//找到根结点后,就能确定sequence[i]的直接根结点了.//且sequence[i-1]也一定是root的左子结点.root = stack.pop();}//每个数字都要进一次栈,且进栈的顺序一定是单调递增的,因为进栈的都是栈底结点的右子结点//因为左子结点需要找自己的直接根结点,找根结点的过程中会出栈.//所以这里用单调栈的意义就是为了保存右子结点,为后续左子结点找根结点提供方式.stack.add(sequence[i]);}return true;}
}

复杂度分析:
时间复杂度:O(n),遍历数组序列。
空间复杂度:O(n),入栈最大数目n。

备注:大部分文字转载自牛客精华题解,有兴趣的可以去看一下。

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

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

相关文章

网络应用层之(1)DHCPv6协议

网络应用层之(1)DHCPv6协议 Author: Once Day Date: 2024年5月26日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 通信网络技术_Once-Day的博客-C…

如何从头搭建一个自己的java库并上传到maven官方仓库

创建代码 在代码库根目录执行maven命令&#xff0c;用于快速生成一个基础的Maven项目 mvn archetype:generate \-DgroupIdcom.mycompany \-DartifactIdmy-maven-project \-Dversion1.0.0 \-DarchetypeArtifactIdmaven-archetype-quickstart \-DinteractiveModefalse 这个命令…

分享一个用AI降本的思路,不懂代码也能上手

如何用AI解决实际的业务问题&#xff1f; 生财圈友我来利用ChatGPT做算法建模&#xff0c;每年为公司省下6万元。 今天他将分享通过ChatGPT进行数据分析的思路&#xff0c;从最开始定义问题到最终数据论证。 上手的实操过程门槛并不高&#xff0c;但可以实现把官方电商平台的…

c++ 虚函数常见问题

1 虚函数&#xff0c;虚表基础 虚函数&#xff0c;虚表基础 2 虚函数表保存在哪里 ? 虚函数表在编译的时候确定。在 linux 下&#xff0c;保存在只读数据段的重定位段&#xff0c;这个段的名字是 .data.rel.ro。 如下代码&#xff0c;编译之后&#xff0c;使用 readelf -t a…

仿《Q极速体育》NBACBA体育直播吧足球直播综合体育直播源码

码名称&#xff1a;仿《Q极速体育》NBACBA体育直播吧足球直播综合体育直播源码 开发环境&#xff1a;帝国cms7.5 空间支持&#xff1a;phpmysql 仿《Q极速体育》NBACBA体育直播吧足球直播综合体育直播源码自动采集 - 我爱模板网源码名称&#xff1a;仿《Q极速体育》NBACBA体育直…

网络攻防概述(基础概念)

文章目录 APTAPT概念APT攻击过程 网络空间与网络空间安全网络空间(Cyberspace)网络空间安全(Cyberspace Security) 网络安全属性机密性(Confidentiality或Security)完整性(Integrity)可用性&#xff08;Availability&#xff09;不可否认性&#xff08;Non-repudiation&#xf…

如何学习计算机网络(超详细,方法论)

分享一下学习计算机网络的方法论 首先是看视频&#xff1a; 这里我推荐中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版》课程 课程目标_哔哩哔哩_bilibili 教材采用神书《计算机网络&#xff08;自顶向下方法&#xff09;》&#xff0c;授课风格更偏向实…

企业如何正确地利用LLM大模型?

大型语言模型 (LLM) 不值得信任。就是这样。 考虑到它们先进的 AI 能力以及当今强大的基础模型的普遍知识&#xff0c;这似乎是一件令人惊讶的事情。然而&#xff0c;问题的关键在于 LLM 无法解释其输出。你不能信任 LLM 的结果&#xff0c;不是因为它不准确&#xff0c;而是因…

无畏并发: Rust Mutex的基本使用

并发是很多编程语言避不开的一块主要内容&#xff0c;主打一个无畏并发的Rust自然也面临这样的挑战。Rust中的Mutex提供了强大的同步原语&#xff0c;确保共享数据的线程安全&#xff0c;这篇文章中&#xff0c;我们会探讨Mutex的使用&#xff0c;从基础的用法到一些高阶内容。…

2024电工杯B题平衡膳食食谱的优化设计及评价原创论文分享

大家好&#xff0c;从昨天肝到现在&#xff0c;终于完成了2024电工杯数学建模B题的完整论文啦。 实在精力有限&#xff0c;具体的讲解大家可以去讲解视频&#xff1a; 给大家看一下目录吧&#xff1a; 目录 摘 要&#xff1a; 10 一、问题重述 14 二&#xff0e;问题分析 …

Python学习---基于HTTP的服务端基础框架搭建案例

整体功能&#xff1a; 1 创建框架构建相关的文件夹 2 创建app,模块文件 3 在 app模块文件中创建application函数(用于处理请求) 4 将request_handler()中的处理逻辑交由app模块的application函数完成 5 app模块的 application函数返回响应报文 6 在application 文件夹中创建一个…

淘工厂订单导出自动化工具

目录 下载安装与运行 主要目的 其他工具的弊端 本工具的优势 视频演示 下载新版后的注意事项 支持的导出项 什么叫一单多拍 常见问题 如何实现快捷登录 导出卡住时如何操作 如何精确导出 下载安装与运行 下载、安装与运行 语雀 主要目的 导出订单信息&#xf…

知识分享:隔多久查询一次网贷大数据信用报告比较好?

随着互联网金融的快速发展&#xff0c;越来越多的人开始接触和使用网络贷款。而在这个过程中&#xff0c;网贷大数据信用报告成为了评估借款人信用状况的重要依据。那么&#xff0c;隔多久查询一次网贷大数据信用报告比较好呢?接下来随小易大数据平台小编去看看吧。 首先&…

某钢铁企业数字化转型规划案例(114页PPT)

案例介绍&#xff1a; 该钢铁企业的数字化转型案例表明&#xff0c;数字化转型是钢铁企业应对市场竞争、提高生产效率、降低成本、优化资源配置和降低能耗排放的重要手段。通过引入先进的技术和管理理念&#xff0c;加强员工培训和人才引进&#xff0c;企业可以成功实现数字化…

欢乐钓鱼大师游戏攻略:自动钓鱼技巧!

《欢乐钓鱼大师》是一款极具趣味性和挑战性的钓鱼模拟游戏&#xff0c;为玩家提供了一个体验钓鱼乐趣的虚拟世界。从湖泊到河流&#xff0c;再到广袤的海洋&#xff0c;游戏中的各种钓场让人流连忘返。无论是新手钓友&#xff0c;还是经验丰富的老钓手&#xff0c;都可以在游戏…

k8s集群中pod的容器资源限制和三种探针

一、资源限制 总结&#xff1a; requests表示创建pod时预留的资源&#xff0c;limits表示pod能够使用资源的最大值。requests值可以被超&#xff0c;limits值不能超过&#xff0c;如果是内存使用超过limits会触发oom然后杀掉进程&#xff0c;如果是cpu超过limits会压缩cpu的使用…

20.SkyWalking

一.简介 SkyWalking用于应用性能监控、分布式链路跟踪、诊断&#xff1a; 参考连接如下&#xff1a; https://github.com/apache/skywalking https://skywalking.apache.org/docs/ 二.示例 通过官网连接进入下载页面&#xff1a;https://archive.apache.org/dist/skywalkin…

揭秘章子怡成功之路:她是如何征服世界的?

章子怡的演艺生涯可谓是一部传奇❗❗❗ 从一个普通工人家庭的女孩&#xff0c;到如今的国际巨星 她的每一步都充满了努力和汗水 她的舞蹈基础为她日后的演艺事业奠定了坚实的基础 而她对戏剧和电影的热爱更是让她在演艺道路上不断前行 从《我的父亲母亲》到《卧虎藏龙》&…

代码随想录|Day55|动态规划 part15|● 392.判断子序列 ● 115.不同的子序列

392.判断子序列 class Solution: def isSubsequence(self, s: str, t: str) -> bool: dp [[0] * (len(t) 1) for _ in range(len(s) 1)] for i in range(1, len(s) 1): for j in range(1, len(t) 1): if s[i - 1] t[j - 1]: dp[i][j] dp[i - 1][j - 1] 1 else: dp[i…

【UE5.1 角色练习】06-角色发射火球-part2

目录 效果 步骤 一、火球生命周期 二、添加可被伤害的NPC 三、添加冲量 在上一篇&#xff08;【UE5.1 角色练习】06-角色发射火球-part1&#xff09;基础上继续实现角色发射火球相关功能 效果 步骤 一、火球生命周期 为了防止火球没有命中任何物体而一直移动下去&#…