网站首页 > 技术文章 正文
题目:
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
限制:
0 <= 节点个数 <= 5000
解析:
这道题很有意思,利用了前序遍历和中序遍历的特点,有两种方法一种递归法,一种迭代法。
第一种:递归法,这也是大多数人的方法。
我们都知道:二叉树的前序遍历是:根节点-左子树-右子树;中序遍历是:左子树-根节点-右子树。那么先用前序遍历判断根节点,然后利用中序遍历中根节点的位置划分左右子树,例如:前序:[3,9,20,15,7],中序:[9,3,15,20,7],在前序中第一个元素是根节点3,在中序中找到3的位置,3的左边是左子树,右边是右子树。接着在前序中找左子树的根节点(就是root节点左边的第一个节点),继续在中序遍历中划分左右子树,以此类推。
在中序遍历中搜索根节点root的索引 ,可将 中序遍历 划分为 [ 左子树 | 根节点 | 右子树 ] 。
根据中序遍历中的左 / 右子树的节点数量,可将 前序遍历 划分为 [ 根节点 | 左子树 | 右子树 ] 。
前序遍历划分 [ 3 | 9 | 20 15 7 ]
中序遍历划分 [ 9 | 3 | 15 20 7 ]
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def buildTree(preorder, inorder) -> TreeNode:
"通过前序遍历和中序遍历结果重建二叉树"
if not preorder: # 递归终止(当前序遍历为空时停止,证明节点都遍历完了)
return None
root = TreeNode(preorder[0])
n = inorder.index(root.val) # 找到根节点在中序遍历中的下标
root.left = buildTree(preorder[1:n + 1], inorder[:n]) # 开启左子树递归
root.right = buildTree(preorder[n + 1:], inorder[n + 1:]) # 开启右子树递归
return root # 回溯返回根节点
第二种:是leetcode官方的方法,迭代法。还是利用前序遍历和中序遍历的特点:前序遍历,从根节点root开始,只要有左子节点,就一直会往左下方走,直到最左下角。(根节点-左子树-右子树),而中序遍历,是从最左下角往上,如果碰到节点有右子节点,则会转向。(左子树-根节点-右子树)
所以按照这个思路:先利用前序遍历数组一直构建左子树,直到到底,然后利用中序遍历数组向上处理右子树。
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def buildTree2(preorder, inorder) -> TreeNode:
"通过前序遍历和中序遍历结果重建二叉树"
if not preorder:
return None
stack = []
# 初始时栈中存放了根节点(前序遍历的第一个节点),指针指向中序遍历的第一个节点;
root = TreeNode(preorder[0])
stack.append(root)
inorderindex = 0
# 依次枚举前序遍历中除了第一个节点以外的每个节点。
for i in range(1, len(preorder)):
preorderval = preorder[i]
node = stack[-1]#获取栈顶元素
if node.val != inorder[inorderindex]: # (如果 index 和栈顶节点不同,我们将当前节点作为栈顶节点的左儿子;)
# 用前序数组一直构建左子树,如果碰到了inorder[inorderIndex]表示到了左下角
node.left = TreeNode(preorderval)
stack.append(node.left)
else:
# while用于继续往上走,处理右节点。
# 如果 index 恰好指向栈顶节点,那么我们不断地弹出栈顶节点并向右移动 index,
while stack and stack[-1].val == inorder[inorderindex]:
node = stack.pop()
inorderindex += 1
# 并将当前节点作为最后一个弹出的节点的右儿子;
node.right = TreeNode(preorderval)
stack.append(node.right)
return root
注意:
用前序遍历数组进行构建的前提是前序遍历数组中的值不等于中序遍历数组中从第一个元素开始的值。因为中序遍历的第一个元素必定是最后的左子树(一定在最下角),要是两者相等,证明前序遍历数组已经到了最下角。然后开始往上走弹出左节点,继续判断栈中剩下的元素是否等于中序遍历中接下来的元素,相等则证明除了左子树外接下来还相等的点一定是根节点,接着处理右子树即可(将右子树赋值给根节点(有可能是局部的根节点,这里泛指左子树之上的节点))。
总结一下,其实就是当前序数组中和数组中序中第一次相同,肯定是到达最左边了-(左子节点),将左子节点出栈后剩下的元素还相等肯定是根节点(回退到根节点处理右子节点)。然后循环这个过程。
- 上一篇: 面向对象 3(面向对象3个特性)
- 下一篇: 零基础小白Python入门必看:面向对象之典型魔术方法
猜你喜欢
- 2024-09-09 序列化 Python 对象(序列化对象需要实现的接口)
- 2024-09-09 一篇文章读懂系列-2.二叉树及常见面试题
- 2024-09-09 Meta 如何将缓存一致性提高到 99.99999999
- 2024-09-09 自学Python笔记2(python0基础自学书)
- 2024-09-09 找到两个链表的第一个公共节点(找出两个链表的第一个公共节点)
- 2024-09-09 详解SkipList跳跃链表(跳表遍历)
- 2024-09-09 Python画豪华版圣诞树,带漂亮彩灯与文字背景
- 2024-09-09 零基础Python完全自学教程23:函数的返回值、作用域和匿名函数
- 2024-09-09 redis的内存满了之后,redis如何回收内存
- 2024-09-09 「python小游戏」据说这是一款还原度超高的小游戏,你感受下....
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)