33. 二叉搜索树的后序遍历序列【难】

news/2024/9/18 15:04:35/ 标签: 算法

comments: true
difficulty: 中等
edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9833.%20%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E5%BA%8F%E5%88%97/README.md

面试题 33. 二叉搜索树的后序遍历序列

题目描述

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

 

参考以下这颗二叉搜索树:

     5/ \2   6/ \1   3

示例 1:

输入: [1,6,3,2,5]
输出: false

示例 2:

输入: [1,3,2,6,5]
输出: true

 

提示:

  1. 数组长度 <= 1000

解法

方法一:递归

后序遍历的最后一个元素为根节点,根据二叉搜索树的性质,根节点左边的元素都小于根节点,根节点右边的元素都大于根节点。因此,我们找到第一个大于根节点的位置 i i i,那么 i i i 右边的元素都应该大于根节点,否则返回 false。然后递归判断左右子树。

时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( n ) O(n) O(n)。其中 n n n 为数组长度。

Python3

【LeetCode力扣刷题 | 剑指Offer 33. 二叉搜索树的后序遍历序列(思路讲解及Python3代码实现)程序员面试手撕代码必刷题库】 https://www.bilibili.com/video/BV1FK4y1j73k/?share_source=copy_web&vd_source=ed4a51d52f6e5c9a2cb7def6fa64ad6a

class Solution:def verifyPostorder(self, postorder: List[int]) -> bool:def dfs(l, r):if l >= r:return Truev = postorder[r] #根节点值i = lwhile i < r and postorder[i] < v:i += 1 #左子树遍历,确保都比根节点小【退出时,i位置为第一个右子树元素的位置】  j=iif any(x < v for x in postorder[j:r]):return False #右子树遍历,并检验是否都比 都比根节点大return dfs(l, j - 1) and dfs(j, r - 1) #递归左右子树return dfs(0, len(postorder) - 1)
Java
class Solution {private int[] postorder;public boolean verifyPostorder(int[] postorder) {this.postorder = postorder;return dfs(0, postorder.length - 1);}private boolean dfs(int l, int r) {if (l >= r) {return true;}int v = postorder[r];int i = l;while (i < r && postorder[i] < v) {++i;}for (int j = i; j < r; ++j) {if (postorder[j] < v) {return false;}}return dfs(l, i - 1) && dfs(i, r - 1);}
}
C++
class Solution {
public:bool verifyPostorder(vector<int>& postorder) {function<bool(int, int)> dfs = [&](int l, int r) -> bool {if (l >= r) {return true;}int v = postorder[r];int i = l;while (i < r && postorder[i] < v) {++i;}for (int j = i; j < r; ++j) {if (postorder[j] < v) {return false;}}return dfs(l, i - 1) && dfs(i, r - 1);};return dfs(0, postorder.size() - 1);}
};
Go
func verifyPostorder(postorder []int) bool {var dfs func(l, r int) booldfs = func(l, r int) bool {if l >= r {return true}v := postorder[r]i := lfor i < r && postorder[i] < v {i++}for j := i; j < r; j++ {if postorder[j] < v {return false}}return dfs(l, i-1) && dfs(i, r-1)}return dfs(0, len(postorder)-1)
}
TypeScript
function verifyPostorder(postorder: number[]): boolean {const dfs = (l: number, r: number): boolean => {if (l >= r) {return true;}const v = postorder[r];let i = l;while (i < r && postorder[i] < v) {++i;}for (let j = i; j < r; ++j) {if (postorder[j] < v) {return false;}}return dfs(l, i - 1) && dfs(i, r - 1);};return dfs(0, postorder.length - 1);
}
Rust
impl Solution {fn dfs(start: usize, end: usize, max_val: i32, postorder: &Vec<i32>) -> bool {if start >= end {return true;}let root_val = postorder[end - 1];for i in (start..end).rev() {let val = postorder[i];if val > max_val {return false;}if val < root_val {return (Self::dfs(start, i, root_val, postorder)&& Self::dfs(i + 1, end - 1, max_val, postorder));}}Self::dfs(start, end - 1, max_val, postorder)}pub fn verify_postorder(postorder: Vec<i32>) -> bool {Self::dfs(0, postorder.len(), i32::MAX, &postorder)}
}
JavaScript
/*** @param {number[]} postorder* @return {boolean}*/
var verifyPostorder = function (postorder) {const dfs = (l, r) => {if (l >= r) {return true;}const v = postorder[r];let i = l;while (i < r && postorder[i] < v) {++i;}for (let j = i; j < r; ++j) {if (postorder[j] < v) {return false;}}return dfs(l, i - 1) && dfs(i, r - 1);};return dfs(0, postorder.length - 1);
};
C#
public class Solution {private int[] postorder;public bool VerifyPostorder(int[] postorder) {this.postorder = postorder;return dfs(0, postorder.Length - 1);}private bool dfs(int l, int r) {if (l >= r) {return true;}int v = postorder[r];int i = l;while (i < r && postorder[i] < v) {++i;}for (int j = i; j < r; ++j) {if (postorder[j] < v) {return false;}}return dfs(l, i - 1) && dfs(i, r - 1);}
}
Swift
class Solution {private var postorder: [Int] = []func verifyPostorder(_ postorder: [Int]) -> Bool {self.postorder = postorderreturn dfs(0, postorder.count - 1)}private func dfs(_ l: Int, _ r: Int) -> Bool {if l >= r {return true}let rootValue = postorder[r]var i = lwhile i < r && postorder[i] < rootValue {i += 1}for j in i..<r {if postorder[j] < rootValue {return false}}return dfs(l, i - 1) && dfs(i, r - 1)}
}

方法二:单调栈【难】

后序遍历的顺序为“左、右、根”,如果我们从右往左遍历数组,那么顺序就变成“根、右、左”,根据二叉搜索树的性质,右子树所有节点值均大于根节点值。

因此,从右往左遍历数组,就是从根节点往右子树走,此时值逐渐变大,直到遇到一个递减的节点,此时的节点应该属于左子树根节点。我们找到该节点,那么此后其它节点【左子树】都应该小于该父节点,否则返回 false。然后继续遍历,直到遍历完整个数组。

此过程,我们借助栈来实现,具体步骤如下:

我们首先初始化一个无穷大的父节点值 m x mx mx,然后初始化一个空栈。

接下来,我们从右往左遍历数组,对于每个遍历到的元素 x x x

-如果 x x x 大于 m x mx mx,说明当前节点不满足二叉搜索树的性质【即左子树的节点 > 左子树根节点】,返回 false
- 否则,如果当前栈不为空,且栈顶元素大于 x x x【根->右,维护递减栈】,说明当前节点为左子树节点,我们循环将栈顶元素出栈并赋值给 m x mx mx,直到栈为空或者栈顶元素小于等于 x x x,然后将 x x x 入栈。

遍历结束后,返回 true

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)。其中 n n n 为数组长度。

【单调栈【基础算法精讲 26】】 https://www.bilibili.com/video/BV1VN411J7S7/?share_source=copy_web&vd_source=ed4a51d52f6e5c9a2cb7def6fa64ad6a
【o(n)找下一个更大元素】

Python3
class Solution:def verifyPostorder(self, postorder: List[int]) -> bool:mx = infstk = []for x in postorder[::-1]:#2)遇到左子树的节点 > 左子树根节点mx【不满足递减栈条件退出时的元素】,返回 `false`if x > mx:return False#1)根->右:维护单调递减栈while stk and stk[-1] > x:mx = stk.pop()stk.append(x)return True
Java
class Solution {public boolean verifyPostorder(int[] postorder) {int mx = 1 << 30;Deque<Integer> stk = new ArrayDeque<>();for (int i = postorder.length - 1; i >= 0; --i) {int x = postorder[i];if (x > mx) {return false;}while (!stk.isEmpty() && stk.peek() > x) {mx = stk.pop();}stk.push(x);}return true;}
}
C++
class Solution {
public:bool verifyPostorder(vector<int>& postorder) {stack<int> stk;int mx = 1 << 30;reverse(postorder.begin(), postorder.end());for (int& x : postorder) {if (x > mx) {return false;}while (!stk.empty() && stk.top() > x) {mx = stk.top();stk.pop();}stk.push(x);}return true;}
};
Go
func verifyPostorder(postorder []int) bool {mx := 1 << 30stk := []int{}for i := len(postorder) - 1; i >= 0; i-- {x := postorder[i]if x > mx {return false}for len(stk) > 0 && stk[len(stk)-1] > x {mx = stk[len(stk)-1]stk = stk[:len(stk)-1]}stk = append(stk, x)}return true
}
TypeScript
function verifyPostorder(postorder: number[]): boolean {let mx = 1 << 30;const stk: number[] = [];for (let i = postorder.length - 1; i >= 0; --i) {const x = postorder[i];if (x > mx) {return false;}while (stk.length && stk[stk.length - 1] > x) {mx = stk.pop();}stk.push(x);}return true;
}
JavaScript
/*** @param {number[]} postorder* @return {boolean}*/
var verifyPostorder = function (postorder) {let mx = 1 << 30;const stk = [];for (let i = postorder.length - 1; i >= 0; --i) {const x = postorder[i];if (x > mx) {return false;}while (stk.length && stk[stk.length - 1] > x) {mx = stk.pop();}stk.push(x);}return true;
};

http://www.ppmy.cn/news/1516491.html

相关文章

破晓科技与神话:三防平板与《黑神话:悟空》的创新交响

当全球游戏圈因《黑神话&#xff1a;悟空》的震撼预告而沸腾&#xff0c;一款代表中国游戏顶尖制作水平的作品&#xff0c;正以它独特的文化魅力与技术创新&#xff0c;向世界宣告着中国游戏产业的崛起。 点击添加图片描述&#xff08;最多60个字&#xff09;编辑 震撼视觉体验…

nginx正向代理与反向代理功能

Nginx是一款高性能的HTTP和反向代理服务器&#xff0c;同时也是一个IMAP/POP3/SMTP代理服务器。它的正向代理和反向代理功能在实际工作中有广泛的应用。 正向代理 功能 正向代理是位于客户端和原始服务器之间的代理服务器。客户端&#xff08;例如浏览器&#xff09;向代理服…

记录一个iOS工程添加文件的问题

遇到一个紧急问题&#xff0c;将工程copy了一份&#xff0c;然后需要将copy工程的一个文件夹 拖到现有的工程里面&#xff0c;由于事情紧急&#xff0c;就直接从工程目录中拖拽文件夹&#xff0c; 如下图 拖过之后&#xff0c;本地项目能跑了&#xff0c;但是远端自动化构建是…

排序算法之选择排序详细解读(附带Java代码解读)

选择排序&#xff08;Selection Sort&#xff09;是一种简单且直观的排序算法。它的基本思想是&#xff1a;每一轮从未排序的部分中选出最小&#xff08;或最大&#xff09;的元素&#xff0c;放到已排序部分的末尾。通过不断地选择最小&#xff08;或最大&#xff09;元素&…

MybatisPlus:实现分页效果并解决错误:cant found IPage for args

我们在做开发使用mybatisplus 做分页查询的时候遇到了个问题&#xff1a; 继承 IPage拦截没有作用会默认分页&#xff0c;这个时候报了cant found IPage for args 错误~~~ 我们分析了下&#xff0c;其实这个问题很简单&#xff0c;是因为没有给默认值赋值&#xff0c;因为查询…

申报合肥市各区县高新技术企业认定奖励补助政策

&#xff08;一&#xff09;合肥市 对首次认定为国家高新技术企业给予10万元奖励&#xff0c;并落实国家各项税收优惠支持政策。对符合条件的入库国家科技型中小企业&#xff0c;按符合加计扣除条件的研发费用10%&#xff0c;给予10万元—50万元补贴。 &#xff08;政策来源&…

鸿蒙高级开发者认证题库(2)

20.项目需要为不同的设备形态(如手机、智能手表)提供定制化构建。请说明如何在DevEco studio中设置不同的构建配置&#xff0c;以生成针对不同设备的hap包? A.在工程级别build-profile.ison5定义多个 product&#xff0c;在每个product的config/deviceType中定义不同的设备类…

攻防世界 1000次点击

做题笔记。 下载解压 查壳。 32位ida打开。 查找字符串。 winmain函数写的&#xff0c;程序运行如下&#xff1a; 一开始思路是想着分析找到关键代码然后去od进行调试。 后来&#xff0c;额&#xff0c;不想看代码了。吐了。 尝试去字符串搜索flag样式&#xff0c;确实一发现…

数据结构(6_3_1)——图的广度优先遍历

树和图的广度优先遍历区别 树的广度优先遍历&#xff1a; 图的广度优先遍历&#xff1a; 代码&#xff1a; 注:以下代码只适合连通图 #include <stdio.h> #include <stdbool.h>#define MAX_VERTEX_NUM 100typedef struct ArcNode {int adjvex; // 该边所指向的顶…

链表(含代码)

好久没更新了&#xff0c;今天浅浅更新一下。 今天给大家主要分享一下链表的一些知识。 链表的首先方式主要有两种&#xff0c;一种是结构体加指针&#xff0c;另一种是拿数组模拟链表。 一、结构体加指针&#xff08;每次都要调用new Node&#xff08;&#xff09;函数&…

优化|计算合作博弈的成本分摊

原文&#xff1a; Caprara, A., & Letchford, A. N. (2010). New techniques for cost sharing in combinatorial optimization games. Mathematical programming, 124, 93-118. https://doi.org/10.1007/s10107-010-0357-7. 原文作者&#xff1a; Alberto Caprara, Adam N…

【功能实现】axios实现动态数据

1.安装axios npm i axios 2.axios调取数据 import { onMounted,ref } from "vue"const titleListref([])//获取数据库数据&#xff0c;将数据赋值给titleListconst getArticles async () > {const result await axios.get(http://127.0.0.1:3000/getAccount)t…

嵌入式Linux学习笔记

1.文件操作命令 2.VI编辑器的部分命令 3.Uboot命令设置环境变量 4. uboot 的顶层 Makefile的重点是“make xxx_defconfig”和“make”这两个命令 &#xff0c;分别如下&#xff1a; 5.在串口SecureCRT中利用uboot启动Linux内核的两种方式 6.Linux内核移植到开发板上也可以反…

C#/.NET/.NET Core技术前沿周刊 | 第 2 期(2024年8.19-8.25)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿&…

MFC之word操作

MFC对word操作 背景说明 当对程序的内容进行输出时&#xff0c;比如自定义对象属性描述或者注释&#xff08;详细设计&#xff09;生成文档时&#xff0c;如果采用手动输入会比较麻烦&#xff0c;并且当程序变动时&#xff0c;需要再一次修改对应文档&#xff0c;作为程序员做…

修复 502 Bad Gateway 错误的 6 种方法

通常&#xff0c;我们在使用网站时可能会遇到一系列错误。有些非常常见&#xff0c;例如 404&#xff0c;有些则不太常见&#xff0c;例如 101。这些被称为 HTTP 状态代码。其中&#xff0c;502 错误是某种服务器错误。那么&#xff0c;让我们先了解一下 Bad Gateway 502 的含义…

EazyDraw for Mac 矢量图绘制设计软件

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功 三、运行测试安装完成&#xff01;&#xff01;&#xff01; 效果 一、下载软件 下载软件…

SpringMvc 以配置类的形式代替xml文件

1、配置类 1.1、创建Mvc 项目之后创建 MyWebApplicationInitializer 类 实现接口 WebApplicationInitializer public class MyWebApplicationInitializer implements WebApplicationInitializer {Overridepublic void onStartup(ServletContext servletContext) throws Serv…

通过Spring Boot创建项目

目录 引言 一、创建新项目 二、通过spring boot创建顾客查询的项目 1.实体类: 2.mapper接口 3.service服务层接口 4.service服务层接口实现类 5.mapper映射文件 三、可能遇到的问题 引言 在通过之前ssm框架的学习后&#xff0c;你是否会感觉ssm的配置过多&#xff0c…

Redis 的 主从复制

目录 1 Redis 主从复制介绍 2 Redis主从复制原理 2.1 主从同步过程 3 Redis实现主从复制 3.1 环境配置 3.2 修改各节点的配置文件 3.2.1 MASTER 3.2.2 SLAVE 3.3.3 重启Redis 3.3 查看是否实现了主从复制 3.3.1 MASTER 3.3.2 SLAVE 3.3.3 Redis 常用操作 3.3.4 数据添加查看…