力扣每日一题打卡 - 构建二叉树专题
这道题是今天(2020-09-25)力扣官方的每日一题, 之前我写了题解,总结了 《构建二叉树专题》[1](可以阅读原文查看)。有一些朋友说我的复杂度有点高,实际上我只是为了新手容易理解才那么写的, 今天稍微修改一下放给大家看。
此题目和105. 从前序与中序遍历序列构造二叉树[2] 完全一致,如果你会其中一个,那么另外一个也一定会。
我们以题目给出的测试用例来讲解:
后序遍历是左右根
,因此postorder最后一个元素一定整个树的根。由于题目说明了没有重复元素,因此我们可以通过val去inorder找到根在inorder中的索引i。而由于中序遍历是左根右
,我们容易找到i左边的都是左子树,i右边都是右子树。
我使用红色表示根,蓝色表示左子树,绿色表示右子树。
根据此时的信息,我们能构造的树是这样的:
其中右子树由于个数大于1,我们无法确定,我们继续执行上述逻辑。我们postorder继续向前移动一位,这个时候我们得到了第二个根节点”20“,实际上就是右子树的根节点。
根据此时的信息,我们能构造的树是这样的:
我们不断执行上述逻辑即可。
代码:
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
# 实际上inorder 和 postorder一定是同时为空的,因此你无论判断哪个都行
if not inorder:
return None
root = 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
简单起见,递归的时候每次我都开辟了新的数组,这个其实是没有必要的,我们可以通过四个变量来记录inorder和postorder的起始位置即可, 具体见下方代码区。
代码
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
def dfs(inorder, in_start, in_end, postorder, post_start, post_end):
if in_start > in_end: return None
if in_start == in_end: return TreeNode(inorder[in_start])
if post_start == post_end: return TreeNode(inorder[in_start])
root = TreeNode(postorder[post_end])
i = inorder.index(root.val)
root.left = dfs(inorder, in_start, i - 1, postorder, post_start, post_start + i - 1 - in_start)
root.right = dfs(inorder, i + 1, in_end, postorder, post_start + i - 1 - in_start + 1, post_end - 1)
return root
n = len(inorder)
return dfs(inorder, 0, n - 1, postorder, 0, n - 1)
「复杂度分析」
- 时间复杂度:由于每次递归我们的inorder和postorder的总数都会减1,因此我们要递归N次,故时间复杂度为
,其中N为节点个数。
- 空间复杂度:我们使用了递归,也就是借助了额外的栈空间来完成, 由于栈的深度为N,因此总的空间复杂度为
,其中N为节点个数。
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。
Reference
[1]
构建二叉树专题: https://lucifer.ren/blog/2020/02/08/%E6%9E%84%E9%80%A0%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%93%E9%A2%98/
[2]
105. 从前序与中序遍历序列构造二叉树: https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/si-lu-qing-xi-dai-ma-jian-ji-he-105ti-si-lu-yi-z-2/
如果觉得文章不错,帮忙点个在看呗
- HDUOJ---------2255奔小康赚大钱
- HDUOJ------1711Number Sequence
- HDUOJ---1712 ACboy needs your help
- HDUOJ---1867 A + B for you again
- HDUOJ--------1420Prepared for New Acmer
- PowerVM虚拟化环境下 CPU 利用率的监控与探究
- 虚函数中构造函数的调用顺序
- HDUOJ-----4512吉哥系列故事——完美队形I(LCIS)
- go语言mongdb管道使用(二)
- HDUOJ--4565 So Easy!
- Go 语言Map(集合)
- 简单的java实验,涉及到 类继承以及接口问题,方法体的重写(区别于重载)
- java 快速求素数
- 狄斯奎诺(dijkstra 模板)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 当删库时如何避免跑路
- Python 句法错误:"SyntaxError: invalid character in identifier",原因及解决方法
- Python3 多线程问题:ModuleNotFoundError: No module named 'thread',原因及解决办法。
- 文件传输和秒传
- 关于数据库的各种备份与还原姿势详解
- Python 技术篇-多线程的2种创建方法,多线程的简单用法,快速上手。
- Python 技术篇-调用浏览器访问指定网页,一行代码实现。非Selenium。
- 数据库热备份神器 - XtraBackup
- Python 技术篇-读取文件,将内容保存dict字典中。去掉字符串中的指定字符方法。dict字典的遍历。
- PyQt5 技术篇-plainTextEdit控件获得文本内容方法、设置文本内容方法。
- PyQt5 技术篇-鼠标移动控件显示提示,Qt Designer控件提示设置方法。
- PyQt5 技术篇-窗口名、窗口图标的设置方法。
- 101个shell脚本
- PyQt5 图片兼容性问题:"libpng warning: bKGD: invalid.",原因及解决办法。
- 编程语言经典小例题—Python版【持续更新】