LeetCode-1008. 前序遍历构造二叉搜索树【栈 树 二叉搜索树 数组 二叉树 单调栈】

LeetCode-1008. 前序遍历构造二叉搜索树【栈 树 二叉搜索树 数组 二叉树 单调栈】

  • 题目描述:
  • 解题思路一:题目大致意思就是给定一个二叉树的前序遍历,求对应的二叉搜索树。一种比较特殊的点是「二叉搜索树」的中序遍历的结果是【有序序列】,故而我们可以对「前序遍历」的结果 【排序】 得到「中序遍历」的结果。从而依据这棵树的前序和中序遍历结果构建该「二叉搜索树」。
  • 解题思路二:二分查找左右子树的分界线递归构建左右子树。可以找到的规律是前序遍历结果第一个是根节点,而后面的元素可以分为两个连续的数组,一个数组所有元素严格小于根节点,另一个数组所有元素严格大于根节点。困难在于快速找到这两个数组的分界线,这里用的是二分法。
  • 解题思路三:根据数值上下界递归构建左右子树,我们使用递归的方法,在扫描先序遍历的同时构造出二叉树。我们在递归时维护一个 (lower, upper) 二元组,表示当前位置可以插入的节点的值的上下界。如果此时先序遍历位置的值处于上下界中,就将这个值作为新的节点插入到当前位置,并递归地处理当前位置的左右孩子的两个位置。否则回溯到当前位置的父节点。
  • 解题思路四:单调栈,思路是维护一个栈顶小栈顶大的单调栈,遍历一遍前序遍历结果。如果当前元素大于栈顶元素,则循环出栈找到其父节点node。如果父节点的元素值小于子节点的元素值,则子节点为右孩子,否则为左孩子。代码逻辑其实很简单。

题目描述:

给定一个整数数组,它表示BST(即 二叉搜索树 )的 先序遍历 ,构造树并返回其根。

保证 对于给定的测试用例,总是有可能找到具有给定需求的二叉搜索树。

二叉搜索树 是一棵二叉树,其中每个节点, Node.left 的任何后代的值 严格小于 Node.val , Node.right 的任何后代的值 严格大于 Node.val。

二叉树的 前序遍历 首先显示节点的值,然后遍历Node.left,最后遍历Node.right。

示例 1:
请添加图片描述
输入:preorder = [8,5,1,7,10,12]
输出:[8,5,10,1,7,null,12]

示例 2:
输入: preorder = [1,3]
输出: [1,null,3]

提示:
1 <= preorder.length <= 100
1 <= preorder[i] <= 10^8
preorder 中的值 互不相同

解题思路一:题目大致意思就是给定一个二叉树的前序遍历,求对应的二叉搜索树。一种比较特殊的点是「二叉搜索树」的中序遍历的结果是【有序序列】,故而我们可以对「前序遍历」的结果 【排序】 得到「中序遍历」的结果。从而依据这棵树的前序和中序遍历结果构建该「二叉搜索树」。

对应的题目是105. 从前序与中序遍历序列构造二叉树,感兴趣的可以看看。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def bstFromPreorder(self, preorder: List[int]) -> Optional[TreeNode]:inorder = sorted(preorder)def myBST(preorder_left: int, preorder_right: int, inorder_left: int, inorder_right: int):if preorder_left > preorder_right:return None# 前序遍历中的第一个节点就是根节点preorder_root = preorder_left# 在中序遍历中定位根节点inorder_root = index[preorder[preorder_root]]# 先把根节点建立出来root = TreeNode(preorder[preorder_root])# 得到左子树中的节点数目size_left_subtree = inorder_root - inorder_left# 递归地构造左子树,并连接到根节点# 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素root.left = myBST(preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1)# 递归地构造右子树,并连接到根节点# 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素root.right = myBST(preorder_left + 1 + size_left_subtree, preorder_right, inorder_root + 1, inorder_right)return rootn = len(preorder)index = {element: i for i, element in enumerate(inorder)}return myBST(0, n-1, 0, n-1)

构造哈希表的目的是为了,O(1)时间找到中序遍历结果中的根节点。
时间复杂度:O(nlogn)排序的结果,构造二叉搜索树的时间复杂度为 O(n)
空间复杂度:O(n)

解题思路二:二分查找左右子树的分界线递归构建左右子树。可以找到的规律是前序遍历结果第一个是根节点,而后面的元素可以分为两个连续的数组,一个数组所有元素严格小于根节点,另一个数组所有元素严格大于根节点。困难在于快速找到这两个数组的分界线,这里用的是二分法。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def bstFromPreorder(self, preorder: List[int]) -> Optional[TreeNode]:def dfs(preorder: List[int], left: int, right: int):if left > right: return Noneroot = TreeNode(preorder[left])if left == right: return rootl, r = left, rightwhile(l < r):mid = int(l + (r - l + 1) / 2)if preorder[mid] < preorder[left]: l = mid # 转到区间[mid, r]else : r = mid -1 # 转到区间[l, mid -1]# 其实最后l=r是最终的分界线root.left = dfs(preorder, left + 1, l)root.right = dfs(preorder, l + 1, right)return rootn = len(preorder)if n==0: return nullreturn dfs(preorder, 0, n-1)

时间复杂度:O(nlogn),在找左右子树分界线的时候时间复杂度为O(logn);
空间复杂度:O(n)

解题思路三:根据数值上下界递归构建左右子树,我们使用递归的方法,在扫描先序遍历的同时构造出二叉树。我们在递归时维护一个 (lower, upper) 二元组,表示当前位置可以插入的节点的值的上下界。如果此时先序遍历位置的值处于上下界中,就将这个值作为新的节点插入到当前位置,并递归地处理当前位置的左右孩子的两个位置。否则回溯到当前位置的父节点。

请添加图片描述

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def bstFromPreorder(self, preorder: List[int]) -> Optional[TreeNode]:n = len(preorder)index = 0def dfs(lowerBound: int, upperBound: int):nonlocal index  # 将index声明为非局部变量if index == n: return Nonecur = preorder[index]if cur < lowerBound or cur > upperBound: return Noneindex += 1root = TreeNode(cur)root.left = dfs(lowerBound, cur)root.right = dfs(cur, upperBound)return rootif n==0: return nullreturn dfs(float('-inf'), float('inf'))

时间复杂度:O(n)
空间复杂度:O(n)

解题思路四:单调栈,思路是维护一个栈顶小栈顶大的单调栈,遍历一遍前序遍历结果。如果当前元素大于栈顶元素,则循环出栈找到其父节点node。如果父节点的元素值小于子节点的元素值,则子节点为右孩子,否则为左孩子。代码逻辑其实很简单。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def bstFromPreorder(self, preorder: List[int]) -> Optional[TreeNode]:n = len(preorder)if n==0: return nullroot = TreeNode(preorder[0])stack= [root]for i in range(1,n,1):node = stack[-1]currentNode = TreeNode(preorder[i])while stack and stack[-1].val < currentNode.val: node = stack.pop()if node.val < currentNode.val: node.right = currentNodeelse : node.left = currentNodestack.append(currentNode)return root

时间复杂度:O(n)仅扫描前序遍历一次。
空间复杂度:O(n)用来存储栈和二叉树。

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

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

相关文章

【UE5】监控摄像头效果(下)

目录 效果 步骤 一、多摄像机视角切换 二、摄像头自动旋转巡视 三、摄像头跟踪拍摄 效果 步骤 一、多摄像机视角切换 1. 打开玩家控制器“MyPlayerController”&#xff0c;添加一个变量&#xff0c;命名为“BP_SecurityCameraArray”&#xff0c;类型为“BP_SecurityCa…

蛋仔派对巅峰对决惊奇舞台必胜打法

Hello!大家好呀&#xff01;蛋仔派对我也开始玩啦&#xff01;本期我们发一个蛋仔派对巅峰对决惊奇舞台的必胜打法吧&#xff01;&#xff08;题外话&#xff1a;我的蛋仔名叫做 酷影kuying 大家能加我的好友吗&#xff1f;我是新手有老手能带我上分嘛&#xff1f;…

企业如何选择合适的信息化管理系统?

一、什么是信息化管理系统 信息化这个词在近年已经被说烂了&#xff0c;在信息化快速发展的时代&#xff0c;越来越多的企业开始意识到信息化管理系统的重要性。信息化管理系统是指一种能够帮助企业或组织有效管理信息资源&#xff0c;提高信息的可靠性、安全性和有效性的软件…

博世汽车产业转型,裁1500人 | 百能云芯

博世&#xff08;Bosch&#xff09;&#xff0c;作为全球领先的汽车零部件制造商&#xff0c;近日宣布了一项战略性的组织调整计划&#xff0c;以更好地适应不断演变的汽车行业需求和技术革新。根据《路透社》的报道&#xff0c;博世计划在2025年底之前&#xff0c;在其位于德国…

Redis基础系列-主从复制

Redis基础系列-主从复制 文章目录 Redis基础系列-主从复制1. 什么是 Redis 主从复制&#xff1f;2. 主从复制有什么好处&#xff1f;3. 如何配置 Redis 主从复制&#xff1f;4. 主从复制的验证4.1 如何查看主从搭建成功4.2 主从常见疑问4.3 主从常见命令 5. 主从复制的原理和工…

掌握1688官方API接口:开启智能商务合作新篇章

当涉及到与1688官方合作的API接口时&#xff0c;以下是一些建议和指导&#xff0c;以帮助您开始编写相关的代码。 了解API接口文档&#xff1a; 在编写与1688官方合作的API接口之前&#xff0c;首先需要了解1688官方提供的API接口文档。您可以在1688开放平台上找到相关的文档…

12.11 作业

1&#xff0c; 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和密码…

王道数据结构课后代码题p150 第13——17 (c语言代码实现)

目录 13.p 和 q 分别为指向该二叉树中任意两个结点的指针&#xff0c;试编写算法 ANCESTOR(ROOT,P,q,r)&#xff0c;找到P和q的最近公共祖先结点 r 14.假设二叉树采用二叉链表存储结构&#xff0c;设计一个算法&#xff0c;求非空二叉树 b的宽度(即具有结点数最多的那一层的结点…

SD-WAN解决企业国际互联组网需求

随着云计算、移动应用和企业全球化的浪潮&#xff0c;实时应用在不同地点之间的传输需求不断增加&#xff0c;涵盖异地办公、视频会议、远程桌面、支付交易系统以及远程医疗等。这些应用的顺畅传输对于企业至关重要&#xff0c;而SD-WAN&#xff08;软件定义广域网&#xff09;…

Spring MVC详解、静态资源访问、拦截器

1. Spring MVC概述 1.1 Spring MVC是什么 SpringMVC是Spring的一个模块&#xff0c;是一个基于MVC设计模式的web框架。 1.2 Spring MVC执行流程。 1.3 组件分析 前端控制器&#xff08;默认配置&#xff09;Dispatcher Servlet 作用&#xff1a;只负责分发请求。可以很好的对…

这样的软件测试面试题,谁面试遇到谁淘汰!!!

88 11.6 自动化测试用例的来源 手工编写测试用例 把原来手工的测试用例&#xff0c;当成自动化测试用例 11.7 自动化测试的优点与缺点 优点: 1、对程序的回归测试更方便 2、可以运行更多更繁琐的测试 3、提高测试效率和准确性&#xff0c;节约时间成本 4、可以执行一些手工测试…

手把手教你玩转ESP8266(原理+驱动)

在嵌入式开发中&#xff0c;无线通信的方式有很多&#xff0c;其中 WIFI 是绕不开的话题。说到 WIFI 通信&#xff0c;就不得不提 ESP8266了。 ESP8266 是一款高性能的 WIFI 串口模块&#xff0c;实现透明传输。只要有一定的串口知识&#xff0c;不需要知道 WIFI 原理就可以上…

作为一个产品经理带你了解Axure的安装和基本使用

1.Axure的简介 Axure是一种强大的原型设计工具&#xff0c;它允许用户创建交互式的、高保真度的原型&#xff0c;以及进行用户体验设计和界面设计。Axure可以帮助设计师和产品经理快速创建和共享原型&#xff0c;以便团队成员之间进行沟通和反馈。Axure提供了丰富的交互组件和功…

Spring--10--Spring Bean的生命周期

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.Spring Bean1.1 什么是 Bean简而言之&#xff0c;bean 是由 Spring IoC 容器实例化、组装和管理的对象。 1.2 Spring框架管理Bean对象的优势 2.Bean的生命周期实例…

西工大网络空间安全学院计算机系统基础实验二(phase_2下——漫漫深夜过后的黎明!!!)

内存地址内存地址中的数注释指向这块内存的寄存器0xffffd0e8函数phase_2的栈帧0xffffd0e40xffffd0f4函数phase_2的栈帧0xffffd0e00x5655b7b0函数phase_2的栈帧0xffffd0dc0x565566ca函数read_six_numbers的返回地址&#xff0c;函数phase_2的栈帧0xffffd0d80x5655af64旧%ebx的值…

SpringIOC之ConditionEvaluator

博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌ 博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+…

一文读懂MySQL基础知识文集(8)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

单目相机测距(3米范围内)二维码实现方案(python代码 仅仅依赖opencv)

总体思路:先通过opencv 识别二维码的的四个像素角位置,然后把二维码的物理位置设置为 cv::Point3f(-HALF_LENGTH, -HALF_LENGTH, 0), //tl cv::Point3f(HALF_LENGTH, -HALF_LENGTH, 0), //tr cv::Point3f(HALF_LENGTH, HALF_LENGTH, 0), //br cv::P…

软件运行原理 - 内存模型 - 栈内存

说明 C/C软件运行时&#xff0c;内存根据使用方式的不同分为堆内存和栈内存&#xff0c;栈内存使用有以下特征&#xff1a; 栈内存使用&#xff08;申请、释放&#xff09;由系统自动分配和释放&#xff0c;程序员不用做任何操作。栈内存重复使用&#xff0c;进入函数时数据入…

什么是特征图?

在卷积神经网络&#xff08;CNN&#xff09;中&#xff0c;特征图是在传递给卷积层的图像上发生卷积操作后卷积层的输出。 特征图是如何形成的&#xff1f; 在上面的插图中&#xff0c;我们可以看到特征图是如何从提供的输入图像中形成的。 要发送到卷积层的图像是一个包含像…