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 = [ ...
随机推荐
- SRP(单一职责)——没有一只能飞能走的鸟
单一职责原则(SRP:Single responsibility principle)又称单一功能原则.它规定一个类应该只有一个发生变化的原因. 一.起因 编码中,需要创建一只小鸟,既能飞,用能走. ...
- MindSpore保存与加载模型
技术背景 近几年在机器学习和传统搜索算法的结合中,逐渐发展出了一种Search To Optimization的思维,旨在通过构造一个特定的机器学习模型,来替代传统算法中的搜索过程,进而加速经典图论等 ...
- n皇后问题的递归和迭代版 leetcode N-Queens
题目如下图: 递归版 class Solution { public: vector<vector<string>> solveNQueens(int n) { vector& ...
- RTTI之dynamic_cast运算符
#include <iostream> #include <cstdlib> #include <ctime> using std::cout; class Gra ...
- 使用JSONassert进行JSON对象对比
在日常工作中,会接到用户提出一张订单,修改后需要记录每次修改的信息,然后需要查看修改前后的差异信息这样的需求.要实现这样的功能方式有很多.下面介绍下JSONassert的简单使用,也方便自己后续使 ...
- docker-compose如何动态配置springboot项目的application.yml的配置
假如我们再springboot的工程中有配置文件 方式1: application.properties里面存在环境变量: #配置数据库链接 spring.datasource.url = jdbc: ...
- oracle 碎片管理和数据文件resize释放表空间和磁盘空间(以及sys.wri$_optstat_histgrm_history过大处理)
随着互联网的快速发展,各行各业的数据量也是与日俱增,而数据库的数据量也是直线增长,但是,如果表DML太多,则可能会在高水位线以下出现太多空白. 因此,只能将数据文件缩小到高水位线,因为高水位线以下有一 ...
- 058.Python前端Django与Ajax
一 Ajax简介 AJAX(Asynchronous Javascript And XML)翻译成中文就是"异步Javascript和XML".即使用Javascript语言与服务 ...
- 使用nuget包下载Entity Framework6.0无法使用模型类与数据库上下文自动生成controller与view
解决方法:卸载掉原有的6.0版本EF,从控制台安装5.0版本的. >工具>库程序包管理器>程序包管理器控制台.在PM>后面输入安装命令. 命令如下 Install-Packag ...
- easyUI中datagrid展示对象下属性以及显示多个子属性(Day_37)
easyUI中datagrid展示对象下属性以及显示多个子属性 显示对象单个属性值 添加formatter属性 <th field="decidedzone" width=& ...