从前中后序遍历构造二叉树,三题无脑秒杀

如果只是前中后序遍历的其中一种,是不可能唯一确定一个二叉树的,必须是其中两个的结合,由此便产生了三道题目,在这里可以全部秒杀。
需要记住的要点是:
前序(根左右)——第一个节点一定是根节点;
中序(左根右)——根节点左边一定是左子树,右边一定是右子树;
后序(左右根)——最后一个节点一定是根节点。

树节点类定义如下:

class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = right

105. 从前序与中序遍历序列构造二叉树

class Solution:def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:if not preorder: # 判断空树return Noneroot = TreeNode(preorder[0])  # 根节点i = inorder.index(root.val)  # 根节点下标为 i,左子树长度也已知为 iroot.left = self.buildTree(preorder[1:i+1], inorder[:i])  # 左子树root.right = self.buildTree(preorder[i+1:], inorder[i+1:])  # 右子树return root

从前序找到根节点,然后找到其在中序的位置 i,则该位置的左边 [:i] 为左子树,右边 [i+1:] 为右子树。因为已知左子树的长度为 i,则前序中的左子树为 [1:i+1],右子树为 [i+1:]。

优化的写法是,递归的时候传入指针而不是传入整个列表,所以列表不变而指针变,左子树的长度是两个指针之差:

class Solution:def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:def myBuildTree(preorder_left: int, preorder_right: int, inorder_left: int, inorder_right: int):if preorder_left > preorder_right:  # 判断空树return Noneroot = TreeNode(preorder[preorder_left])  # 根节点inorder_root = inorder.index(root.val)  # 根节点下标size_left_subtree = inorder_root - inorder_left  # 左子树长度root.left = myBuildTree(preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1)  # 左子树root.right = myBuildTree(preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right)  # 右子树return rootn = len(preorder)return myBuildTree(0, n - 1, 0, n - 1)

更加优化的写法,是用一个字典(哈希映射)记录下中序列表中数值与下标位置的关系,方便快速找到根的位置:

class Solution:def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:def myBuildTree(preorder_left: int, preorder_right: int, inorder_left: int, inorder_right: int):if preorder_left > preorder_right:  # 判断空树return Noneroot = TreeNode(preorder[preorder_left])  # 根节点inorder_root = index[root.val]  # 根节点下标size_left_subtree = inorder_root - inorder_left  # 左子树长度root.left = myBuildTree(preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1)  # 左子树root.right = myBuildTree(preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right)  # 右子树return rootn = len(preorder)# 构造哈希映射,帮助我们快速定位根节点index = {element: i for i, element in enumerate(inorder)}return myBuildTree(0, n - 1, 0, n - 1)

106. 从中序与后序遍历序列构造二叉树

class Solution:def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:if not inorder: # 判断空树return Noneroot = TreeNode(postorder[-1])i = inorder.index(root.val)root.left = self.buildTree(inorder[:i], postorder[:i])root.right = self.buildTree(inorder[i+1:], postorder[i:-1])return root

从后序找到根节点,然后找到其在中序的位置 i,则该位置的左边 [:i] 为左子树,右边 [i+1:] 为右子树。因为已知左子树的长度为 i,则后序中的左子树为 [:i],右子树为 [i:]。优化写法如下:

class Solution:def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:def mybuildTree(inorder_left:int, inorder_right:int, postorder_left:int, postorder_right:int):if inorder_left > inorder_right:  # 判断空树return Noneroot = TreeNode(postorder[postorder_right])  # 根节点inorder_root = index[root.val]size_left_subtree = inorder_root - inorder_left  # 左子树长度root.left = mybuildTree(inorder_left, inorder_root - 1, postorder_left, postorder_left + size_left_subtree - 1)  # 左子树root.right = mybuildTree(inorder_root + 1, inorder_right, postorder_left + size_left_subtree, postorder_right - 1)  # 右子树return rootn = len(inorder)# 构造哈希映射,帮助我们快速定位根节点index = {element: i for i, element in enumerate(inorder)}return mybuildTree(0, n-1, 0, n-1)

889. 根据前序和后序遍历构造二叉树

class Solution:def constructFromPrePost(self, preorder: List[int], postorder: List[int]) -> TreeNode:if not preorder: # 判断空树return Noneroot = TreeNode(preorder[0])if len(preorder) == 1:  # 下面用到了pre[1],则必须确保长度大于1return rooti = postorder.index(preorder[1])root.left = self.constructFromPrePost(preorder[1:i+2], postorder[:i+1])root.right = self.constructFromPrePost(preorder[i+2:], postorder[i+1:-1])return root

从前序找到根节点,可知其下一个节点是左子节点(左子树的根节点),在后序中找到其位置 i,则该位置的左边 [:i+1] 为左子树,右边 [i+1:] 为右子树。因为已知左子树的长度为 i,则前序中的左子树为 [1:i+2],右子树为 [i+2:-1]。注意一个知识点:前序和后序不能唯一确定一棵二叉树,因为没有中序遍历无法确定左右部分,也就是无法分割。优化写法如下:

class Solution:def constructFromPrePost(self, preorder: List[int], postorder: List[int]) -> TreeNode:def myconstruct(preorder_left, preorder_right, postorder_left, postorder_right):if preorder_left > preorder_right:return Noneroot = TreeNode(preorder[preorder_left])if preorder_left == preorder_right:return rootpostorder_left_root = index[preorder[preorder_left+1]]size_left_subtree = postorder_left_root - postorder_leftroot.left = myconstruct(preorder_left + 1, preorder_left + size_left_subtree + 1, postorder_left,postorder_left + size_left_subtree)root.right = myconstruct(preorder_left + size_left_subtree + 2, preorder_right, postorder_left + size_left_subtree + 1, postorder_right - 1)return rootn = len(preorder)index = {element: i for i, element in enumerate(postorder)}return myconstruct(0, n-1, 0, n-1)

总结:三道题的关键,就是从前序或者后序遍历找到根节点,然后使用根节点或者根节点的左子节点来区分左右子树,完成递归。可以注意到,递归的时候:preorder 肯定没有第一个(根节点),inorder肯定没有第 i 个,postorder肯定没有最后一个;然后根据区分左右子树时用的是根节点还是它的左子节点,决定是 i 还是 i + 1。

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

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

相关文章

.NET Core + Kubernetes:StatefulSet

在 Kubernetes 中,Pod 资源的控制器 Deployment、Replicaset、Daemonset 等常用于管理无状态应用,它们所管理的 Pod 对应的 IP、名字,启停顺序等都是随机的,Pod 之间也并不存在任何关联关系。而实际情况下,在应用集群部…

哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之上——原理与设计

哈希表(Hash table,也叫散列表),是根据键(Key)而直接访问数据在内存中的储存位置(又叫做存储桶,Buckets)的数据结构。也就是说,它通过计算一个关于键值的函数…

python编程中的小问题汇总

前言 本文记录了我在python编程中遇到的各种小问题,持续更新。 1. x x 1 VS x 1 辨析下面这两段代码: >>> x y [1, 2, 3, 4] >>> x [4] >>> x [1, 2, 3, 4, 4] >>> y [1, 2, 3, 4, 4]>>> x y …

都在讨论高并发,结果连并发量、TPS、QPS都分不清

“ 年年岁岁跳槽季,回回必问高并发!原因很简单,因为高并发能牵扯出太多问题,接口响应超时、CPU负载升高、GC频繁、死锁、大数据量存储等,能考察求职者的真实情况。而很多人在第一步就倒下了!因为对数据化的…

哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之中——实际应用

上一节介绍了哈希表的原理与设计方法,这一节则直接python中现有的哈希表类型:哈希集合 set(集合)和哈希映射 dict(字典)来解决实际应用(刷题)。 零、概念 在介绍实际应用之前&#…

leetcode518. 零钱兑换 II

一:题目 二:上码 class Solution { public:/**思路:1.分析题意这个满足答案的结果有很多种,所以我们可以用动态规划去做,那么题意中我们可以知道的是我们是可以输入一种面值的时候,我们是可以重复输入的,那么这就是背包类型中的完全背包了2.动态规划5步…

跟我一起学.NetCore之选项(Options)核心类型简介

前言.NetCore中提供的选项框架,我把其理解为配置组,主要是将服务中可供配置的项提取出来,封装成一个类型;从而服务可根据应用场景进行相关配置项的设置来满足需求,其中使用了依赖注入的形式,使得更加简单、…

哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之下——设计键

在很多应用中,我们会发现某种映射关系(模式),但它并不是简单一 一对应的。这时,我们就要从键 key 入手,通过设计合适的键,建立映射关系。leetbook的这个章节总结了一些常见的键,以供…

《ASP.NET Core项目开发实战入门》送书活动结果公布

截至2020.09.20 本次送书活动《ASP.NET Core项目开发实战入门》。下面把Top 5的留言截图给大家回顾一下。以下5位同学将获赠书籍一本:小林子鉴静红脸先生阿星Plus以上同学请在2020年9月25日24:00之前加小二微信领取赠书,超过时间视为放弃。小…

二分查找基础概念与经典题目(Leetcode题解-Python语言)二分索引型

二分查找的定义如下(引自Wiki): 在计算机科学中,二分查找算法(英语:binary search algorithm),也称折半搜索算法(英语:half-interval search algorithm&…

Magicodes.IE 2.3重磅发布——.NET Core开源导入导出库

在2.3这一版本的更新中,我们迎来了众多的使用者、贡献者,在这个里程碑中我们也添加并修复了一些功能。对于新特点的功能我将在下面进行详细的描述,当然也欢迎更多的人可以加入进来,再或者也很期待大家来提issues或者PR&#xff0c…

听说用 C# 写 TensorFlow 更高效?

经过半年呕心沥血的努力,SciSharp STACK终于把Tensorflow .NET绑定升级到可以使用 tensorflow 2.3, 新版本最大的优势是实现了Eager模式, 这个特性是让.NET C#/ F#成为机器学习模型开发工具的重要前置条件。NugGet包下载:https://www.nuget.org/packages/TensorFlow…

leetcode279. 完全平方数

一:题目 二:上码 class Solution { public:/**思路:1.分析题意这个就是将一个数分成几个数的和;然而的话,这几个数必须的是完全平方数,我们要求的是最少数量的完全平方数这个满足答案的有好几个;但是我们要求的是最少的数量2.动态规划五步走1>:确定dp数组的含义以及下标的含…

岛屿类问题的广度优先深度优先双解法(Leetcode题解-Python语言)

695. 岛屿的最大面积 先上最经典的题目,详细思路看这题的官方题解,简单来说的岛屿问题就是遍历二维数组,一般都是从一块陆地开始,进行深度优先或者广度优先搜索,每次上下左右四个方向选其一然后寻找下一块陆地&#x…

跟我一起学.NetCore之Options实例演示及分析

前言来啦!来啦!上一节一堆代码,是不是感觉甚是无味啊?没关系,这里结合上一节内容专注举例演示,绝不废话!走起~~~~~正文老规矩,一个WebApi项目走起,项目结构如下&#xff…

leetcode139. 单词拆分

一:题目 二:上码 class Solution { public:/**思路:1.分析题意单词就是物品;字符串就是背包;单词能否组成字符串就是在问,物品能不能将背包装满单词可以重复使用那么说明这是一个完全背包2.动态规划五步走1>:确定dp数组的与下标的含义(这里用下标i是由我们的遍历…

二分查找基础概念与经典题目(Leetcode题解-Python语言)二分数值型

二分查找的讲解请见上一篇文章。本文主要记录对数值进行二分的题目解法与思路。 374. 猜数字大小 class Solution:def guessNumber(self, n: int) -> int:left 1right nwhile left < right:mid left (right - left) // 2if guess(mid) 1: # mid < pickleft mi…

大数据下的质量体系建设

一、背景大数据、人工智能是当前也是未来几年IT部门的重点建设方向&#xff0c;新的技术可以为业务突破盈利瓶颈&#xff0c;带来新的增长点&#xff0c;同时我们也发现数据中台也频频在最近的企业财报予以体现&#xff0c;相关的技术岗位需求也是供不应求&#xff0c;与之形成…

Pandas中的 transform() 结合 groupby() 用法示例

首先&#xff0c;假设我们有如下餐厅数据集&#xff1a; import pandas as pddf pd.DataFrame({restaurant_id: [101,102,103,104,105,106,107],address: [A,B,C,D, E, F, G],city: [London,London,London,Oxford,Oxford, Durham, Durham],sales: [10,500,48,12,21,22,14] })…

跟我一起学.NetCore之日志(Log)模型核心

前言鲁迅都说&#xff1a;没有日志的系统不能上线(鲁迅说&#xff1a;这句我没说过&#xff0c;但是在理)&#xff01;日志对于一个系统而言&#xff0c;特别重要&#xff0c;不管是用于事务审计&#xff0c;还是用于系统排错&#xff0c;还是用于安全追踪.....都扮演了很重要的…