剑指Offer07 重建二叉树
剑指 Offer 07. 重建二叉树
前置概念:
前序:访问根节点,先序遍历左子树,先序遍历右子树;
中序:中序遍历左子树,访问根节点,中序遍历右子树;
后序:后序遍历左子树,后序遍历右子树,访问根节点;
图示:

前序:A- B-D-G-H-E-C-F
中序:G-D-H-B-E-A-C-F
后序:G-H-D-E-B-F-C-A
怎么构建一棵树:
通过一组(前序-中序 或 中序-后序)来确定唯一一棵树;
以该题的测试样例举例:
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
前序的第一个数是根节点,在pre数组中找到根节点(3),然后在中序遍历中找到3的位置,那么中序遍历中3左边的(9)就是根节点的左子树(左节点),(15、20、7)就是根节点的右子树(右节点).
通过以上规律可得到一颗树,即:

解题思路如下:
重建二叉树的重构函数分为三个步骤:
- 首先要找到当前元素节点,即pre中的第一个,
- 接着在中序遍历中找到它的左右子树(此处表现为对前序数组、中序数组的分割操作),以便构造他的左右孩子。
- 最后再将左右子树在分别放到重构函数中。
比如此时,我们找到3的右子树(20、15、7),如下图,它实质上适合上图一样的,只不过此时是以3为根节点,其他操作是一样。

前序:3-20-15-7
中序:3-15-20-7
此时重复操作:找到当前元素节点,即前序中的第一个,接着便可以在中序遍历中找到他的左右子树,以便构造他的左右孩子。发现他没有左子树,将左孩子放入构造函数中,如图所示:

前序:20-15-7
中序:15-20-7
此时重复操作:找到当前元素节点,即前序中的第一个,接着便可以在中序遍历中找到他的左右子树,以便构造他的左右孩子。将左右孩子放入重构函数中,即

直到分割成叶子节点,不存在左右子树,他无法再进行分割,故返回自己。叶子节点返回后,其父节点的左右子树分别有了指向,便返回,一步一步向上返回,最后会返回整个二叉树。
通过两段代码来学习该题目:
主要是通过第一段代码来理解第二部分的思想。
第一部分代码段:
leetcode官方题解:详细解释就不说了,重点关注下:size_left_subtree变量(左子树中的节点数目);
- 通过map的key值可以找到中序中的根节点——————>构造哈希映射,帮助我们快速定位根节点
class Solution {
private Map<Integer, Integer> indexMap;
public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
if (preorder_left > preorder_right) {
return null;
}
// 前序遍历中的第一个节点就是根节点
int preorder_root = preorder_left;
// 在中序遍历中定位根节点
int inorder_root = indexMap.get(preorder[preorder_root]);
// 先把根节点建立出来
TreeNode root = new TreeNode(preorder[preorder_root]);
// 得到左子树中的节点数目
int size_left_subtree = inorder_root - inorder_left;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root.left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
return root;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
// 构造哈希映射,帮助我们快速定位根节点
indexMap = new HashMap<Integer, Integer>();
for (int i = 0; i < n; i++) {
indexMap.put(inorder[i], i);
}
return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
}
}
第二部分代码段:
class Solution {
public TreeNode buildTree(int [] pre,int [] in) {
TreeNode root=ConstructCore(pre,0,pre.length-1,in,0,in.length-1);
return root;
}
public TreeNode ConstructCore(int[] pre,int startPre,int endPre,int[] in,int startIn,int endIn)
{
//前序起点下标>前序终点下标 || 中序的起点下标 > 中序终点下标
if(startPre>endPre||startIn>endIn)
return null;
//通过起点下标找到前序中的根节点,并创建
TreeNode node = new TreeNode(pre[startPre]);
//中序遍历
for(int i=startIn;i<=endIn;i++)
{ //在中序中找到了根节点 此时i就是根节点的下标
if(in[i]==pre[startPre])
{
//ConstructCore(前序遍历,前序左子树起点下标,前序左子树终点下标,中序遍历,中序左子树起点下标,中序左子树终点下标)
node.left = ConstructCore(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
node.right =ConstructCore(pre,startPre+i-startIn+1,endPre,in,i+1,endIn);
break;
}
}
return node;
}
}
上述代码最难理解部分如下:
for(int i=startIn;i<=endIn;i++)
{ //在中序中找到了根节点 此时i就是根节点的下标
if(in[i]==pre[startPre])
{
node.left = ConstructCore(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
node.right =ConstructCore(pre,startPre+i-startIn+1,endPre,in,i+1,endIn);
break;
}
}
我们分析node.left以及node.right:
node.left = ConstructCore(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
ConstructCore(前序遍历数组,前序左子树起点下标(除去根节点),前序左子树终点下标,中序遍历,中序左子树起点下标,中序左子树终点下标)
详解: startPre+i-startIn
“ i ” 是当前根节点的下标, i-startin --->表示在左子树中的节点数目,前序左子树
startPre+i-startIn--->表示了前序数组中左子树的终止下标

node.right =ConstructCore(pre,startPre+i-startIn+1,endPre,in,i+1,endIn);
ConstructCore(前序遍历,前序右子树起点下标,前序右子树终点下标,中序遍历,中序右子树起点下标,中序右子树终点下标)
i-startin --->表示在左子树中的节点数目,
startPre+i-startIn--->前序左子树终点下标
startPre+i-startIn+1 ---->前序右子树起点下标
i-1 -->中序右子树起点下标。
参考文献:
代码引自:重建二叉树--->https://www.cnblogs.com/MrSaver/p/9205436.html
LeetCode剑指offer官方题解
剑指Offer07 重建二叉树的更多相关文章
- 剑指Offer-4.重建二叉树(C++/Java)
题目: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2 ...
- 牛客_剑指offer_重建二叉树,再后续遍历_递归思想_分两端
总结: 重建二叉树:其实就是根据前序和中序重建得到二叉树,得到后续,只要输出那边设置输出顺序即可 [编程题]重建二叉树 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的 ...
- 剑指offer--4.重建二叉树
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2, ...
- 剑指Offer——重建二叉树
题目描述: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7 ...
- 剑指Offer——重建二叉树2
Question 输入某二叉树的后序遍历和中序遍历的结果,请重建出该二叉树.假设输入的后序遍历和中序遍历的结果中都不含重复的数字.例如输入后序遍历序列{1, 3, 4, 2}和中序遍历序列{1, 2, ...
- 剑指offer--19.重建二叉树
先序:根>左>右 中序:左>根>右 后序:左>右>根 e.g. {1,2,4,7,3,5,6,8} {4,7,2,1,5,3,8,6} 先序第一个元素是根节点,在中 ...
- 用js刷剑指offer(重建二叉树)
题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7, ...
- 剑指Offer04 重建二叉树
代码有问题 /************************************************************************* > File Name: 04_ ...
- 剑指offer 重建二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...
- 《剑指offer》 二叉树的镜像
本题来自<剑指offer>二叉树的镜像 题目: 操作给定的二叉树,将其变换为源二叉树的镜像. 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 ...
随机推荐
- 第65篇 AJAX初识 校验用户名 登录示例 文件上传 csrftoken
1, 知识储备 2. AJAX的定义 异步的JavaScript和XML 使用场景: JavaScript和后端的数据传递 2.1原生的JavaScript实现AJAX 2.2 JQuery实现 2. ...
- zookeeper源码(02)源码编译启动及idea导入
本文介绍一下zookeeper-3.9.0源码下载.编译及本地启动. 下载源码 git clone https://gitee.com/apache/zookeeper.git cd zookeepe ...
- Meta AI新发布的超大规模语言模型-OPT-175B
Meta AI在2022年5月3日新发布的OPT-175B模型,该模型是现阶段第一个模型参数超过千亿级别的开放模型,其次该模型与GPT-3相比,更加开放及便于访问. 具体开放性表现在如下几个方面: ...
- MAUI使用Masa blazor组件库
上一篇(点击阅读)我们实现了UI在Web端(Blazor Server/Wasm)和客户端(Windows/macOS/Android/iOS)共享,这篇我加上 Masa Blazor组件库的引用,并 ...
- [转帖]nginx配置文件中对于if条件语句的写法(附nginx跨域文件配置)
前言 在nginx配置文件中,可以使用if语句,但是对于else语句其实是不支持的,并且and条件和or条件也是不支持的 实现 else条件的写法 新建一个开关变量flag,初始值为0,如果为1说明进 ...
- Windows平台的prometheus和Grafana的学习与使用
Windows平台的prometheus和Grafana的学习与使用 背景 最近没有了linux机器 突然想捯饬一下Windows平台的监控与使用 所以总结一一下. 第一步下载 https://pro ...
- SPECJVM2008 再学习
SPECJVM2008 再学习 摘要 昨天的太水了 感觉今天有必要再水一点.. 存在的问题 默认进行启动 sunflow 必定过不去. 一般的解决办法要求进行重新编译 但是我不知道怎么下载源码... ...
- Docker 安装Oracle12c的镜像修改字符集 并且进行启动的简单过程
学习来自 昨天晚上转帖的文章 这里面添加一些自己的内容 首先获取配置文件 git clone https://github.com/oracle/docker-images.git 获取之后比较容易了 ...
- 一文带你搞懂如何优化慢SQL
作者:京东科技 宋慧超 一.前言 最近通过SGM监控发现有两个SQL的执行时间占该任务总执行时间的90%,通过对该SQL进行分析和优化的过程中,又重新对SQL语句的执行顺序和SQL语句的执行计划进行了 ...
- js下拉加载更多-详解
场景 有些时候,我们在pc端经常会遇见滚动到底部的时候,去加载下一页的数据, 这个时候,我们就需要知道滚动条什么时候触底了, 如果触底了,就去加载下一页的数据; 在触底的过程中,我们需要注意的是,防止 ...