LeetCode---105. 从前序与中序遍历序列构造二叉树 (Medium)
题目:105. 从前序与中序遍历序列构造二叉树
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
第一种解法:递归解
首先
前序遍历: 根 -> 左-> 右
中序遍历:左 -> 根 -> 右
从前序遍历我们可以知道第一个元素3是根节点,再根据中序遍历我们可以知道从第1个元素到根节点3之间的元素是全部都是根节点的左子树,那么我们就可以从中序遍历来得知该根节点左子树元素的个数,假设为x,从而可以得出根节点左子树元素在前序遍历中的区间是多少,而在知道左子树区间之后,根节点右子树在前序遍历中的区间我们也可以知道,参照下图去理解
比如说下面这棵树:
前序遍历:3 9 6 8 20 15 7
中序遍历:6 9 8 3 15 20 7
3
/ \
9 20
/ \ / \
6 8 15 7

根据代码进一步去理解
代码
class Solution {
// 递归解
int[] preorder;
Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
int len = preorder.length;
this.preorder = preorder;
//将中序遍历所有值放在哈希表中,以减少每次在中序遍历中寻找root值下标的时间,空间换时间
for (int i = 0; i < len; i++) {
map.put(inorder[i], i);
}
return buildTree(0, len - 1, 0, len - 1);
}
/**
* @param preLeft : 前序遍历左边界
* @param preRight : 前序遍历右边界
* @param inLeft : 中序遍历左边界
* @param inRight : 中序遍历右边界
* @return
*/
private TreeNode buildTree(int preLeft, int preRight, int inLeft, int inRight) {
// 递归终止条件,如果左边界大于右边界,递归终止,开始向上一层返回结果
if (preLeft > preRight || inLeft > inRight) {
return null;
}
// 获取当前根节点的值
int temp = preorder[preLeft];
// 创建根节点
TreeNode root = new TreeNode(temp);
// 获取根节点在中序遍历中的下标值
int pIndex = map.get(temp);
// 递归获取当前根节点的左子树
// 其中 前序遍历左子树的右边界 = pIndex - 1 - inLeft + preLeft + 1 = pIndex - inLeft + preLeft
root.left = buildTree(preLeft + 1, pIndex - inLeft + preLeft, inLeft, pIndex - 1);
// 递归获取当前根节点的右子树
root.right = buildTree(pIndex - inLeft + preLeft + 1, preRight, pIndex + 1, inRight);
return root;
}
}
第二种解法:迭代
迭代是一种很巧妙地的解法
继续看下面这颗树
前序遍历:3 9 6 8 20 15 7
中序遍历:6 9 8 3 15 20 7
3
/ \
9 20
/ \ / \
6 8 15 7
首先,我们先只看前序遍历
- 遇到第一个元素
3,那么3肯定是作为根节点 - 遇到第二个元素
9,那么9可能是左子树也可能是右子树,此时我们结合中序遍历来看,中序遍历的第一个元素是6,那么我们就可以确定9是左子树,因为假如9是右子树,那么中序遍历的第一个元素应该是根节点3,但此时很明显不是3,所以可以确定9是左子树 - 再继续往前走,遇到了元素
6,同理,6是元素9的左子树,但此时我们发现6与中序遍历第一个元素相等了,这说明左子树已经遍历到了末尾,下一个元素只能是右子树,但究竟是元素6的右子树?还是元素9的右子树?又或者是元素3的右子树?好,我们接着 往下看 - 现在是遇到了元素
8,我们现在有三种情况- 第一种情况:元素
8是元素6的右子树,那么此时中序遍历的结果就应该是6、8、9、3... - 第二种情况:元素
8是元素9的右子树,此时中序遍历的结果应该是6、9、8、3... - 第三种情况:元素
8是元素3的右子树,此时中序遍历的结果是6、9、3、8...
- 第一种情况:元素
- 我们知道,第二种情况是与我们的中序遍历结果相符合的,所以当我们倒序遍历已经遇到过的元素时,当前遍历的元素
8倒序遍历中最后一个相等的元素9的右子树,而符合可以倒序遍历已经遍历过元素的数据结构就是栈,我们可以用栈来存储已经遍历过的元素。 - 以此类推,我们可以构造完整棵树
代码
class Solution {
//迭代,栈,从后往前遍历解
public TreeNode buildTree2(int[] preorder, int[] inorder) {
Deque<TreeNode> stack = new ArrayDeque<>();
int pre = 0;
int in = 0;
//构造当前正在遍历的节点
TreeNode curRoot = new TreeNode(preorder[pre]);
TreeNode root = curRoot;
stack.push(curRoot);
pre++;
while (pre < preorder.length) {
if (curRoot.val == inorder[in]) {
// 如果当前遍历节点值与中序遍历值相等,不断将栈中元素顶出栈,直到值不相等
while (!stack.isEmpty() && stack.peek().val == inorder[in]) {
curRoot = stack.peek();
stack.pop();
in++;
}
// 当前遍历的节点就是最后一个值相等的节点的右子树
curRoot.right = new TreeNode(preorder[pre]);
curRoot = curRoot.right;
stack.push(curRoot);
pre++;
} else {
//如果值不相等就说明是左子树
curRoot.left = new TreeNode(preorder[pre]);
curRoot = curRoot.left;
stack.push(curRoot);
pre++;
}
}
return root;
}
}
拓展
趁着手热,可以去做一下这道题:106. 从中序与后序遍历序列构造二叉树
LeetCode---105. 从前序与中序遍历序列构造二叉树 (Medium)的更多相关文章
- Java实现 LeetCode 105 从前序与中序遍历序列构造二叉树
105. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中 ...
- [LeetCode]105. 从前序与中序遍历序列构造二叉树(递归)、108. 将有序数组转换为二叉搜索树(递归、二分)
题目 05. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 题解 使用HashMap记录当前子树根节点在中序遍历中的位置,方便每次 ...
- 【leetcode 105. 从前序与中序遍历序列构造二叉树】解题报告
前往 中序,后序遍历构造二叉树, 中序,前序遍历构造二叉树 TreeNode* build(vector<int>& preorder, int l1, int r1, vecto ...
- LeetCode 105. 从前序与中序遍历序列构造二叉树(Construct Binary Tree from Preorder and Inorder Traversal)
题目描述 根据一棵树的前序遍历与中序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9, ...
- Leetcode 105. 从前序与中序遍历序列构造二叉树
题目链接 题目描述 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder ...
- leetcode 105从前序与中序遍历序列构造二叉树
方法一:直接使用复制的数据递归:O(n)时间,O(n)空间,不计算递归栈空间: /** * Definition for a binary tree node. * struct TreeNode { ...
- Leetcode:105. 从前序与中序遍历序列构造二叉树&106. 从中序与后序遍历序列构造二叉树
Leetcode:105. 从前序与中序遍历序列构造二叉树&106. 从中序与后序遍历序列构造二叉树 Leetcode:105. 从前序与中序遍历序列构造二叉树&106. 从中序与后序 ...
- LeetCode 中级 - 从前序与中序遍历序列构造二叉树(105)
一个前序遍历序列和一个中序遍历序列可以确定一颗唯一的二叉树. 根据前序遍历的特点, 知前序序列(PreSequence)的首个元素(PreSequence[0])为二叉树的根(root), 然后在中 ...
- 【LeetCode】105#从前序与中序遍历序列构造二叉树
题目描述 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9 ...
- 【2】【leetcode-105,106】 从前序与中序遍历序列构造二叉树,从中序与后序遍历序列构造二叉树
105. 从前序与中序遍历序列构造二叉树 (没思路,典型记住思路好做) 根据一棵树的前序遍历与中序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [ ...
随机推荐
- hdu4994 博弈,按顺序拿球
题意: 给你n堆东西,两个人博弈的去拿,每次最少一个,最多是一堆,必须按顺序那,也就是只有把第一堆的东西拿完了才能去拿第二堆东西,谁先拿完谁胜,问新手是否能胜利. 思路: 显然 ...
- xposed结合Zygote分析
android中zygote相信大家都很熟悉,它执行的函数是app_main.cpp,而xposed主要实现的就是替换app_main.cpp.所以在分析xposed时有必要来认识下zygote.好了 ...
- Linux系统登录相关
whoami:查看当前用户 who:查看当前登录系统的所有用户 tty指的是主机的图形化界面的面板 pts/x指的是远程ssh连接的窗口 who -b:主机的上一次启动时间 w:显示已经登陆系统的用户 ...
- 基于ray的分布式机器学习(一)
基本思路:1.对数据分块,使用多个worker分别处理一个数据块,每个worker暴露两个接口,分别是损失计算的接口loss和梯度计算的接口grad:2.同时定义full_loss和full_grad ...
- 记一次 .NET 某旅行社Web站 CPU爆高分析
一:背景 1. 讲故事 前几天有位朋友wx求助,它的程序内存经常飙升,cpu 偶尔飙升,没找到原因,希望帮忙看一下. 可惜发过来的 dump 只有区区2G,能在这里面找到内存泄漏那真有两把刷子..., ...
- 『居善地』接口测试 — 4、Requests库发送GET请求
目录 1.使用Requests库发送带参数的GET请求 2.查看GET请求的内容 3.带请求头.参数的Get请求 Requests库GET请求是使用HTTP协议中的GET请求方式对目标网站发起请求. ...
- Python数模笔记-NetworkX(2)最短路径
1.最短路径问题的常用算法 最短路径问题是图论研究中的经典算法问题,用于计算图中一个顶点到另一个顶点的最短路径. 1.1 最短路径长度与最短加权路径长度 在日常生活中,最短路径长度与最短路径距离好像并 ...
- [网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序]
[网络编程之Socket套接字介绍,套接字工作流程,基于TCP协议的套接字程序] 为何学习socket套接字一定要先学习互联网协议: 1.首先:要想开发一款自己的C/S架构软件,就必须掌握socket ...
- 《Ray Tracing in One Weekend》阅读笔记 - 9、Metal(金属)
如果我们希望不同的物体使用不同的材料,则需要进行设计决策.我们可以使用具有许多参数的通用材料,而将不同的材料类型仅将其中一些参数归零.这不是一个坏方法.或者我们可以有一个抽象的材料类来封装行为.我是后 ...
- JAVA 面试相关
1. int和Integer有什么区别? 答:Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类 ...