根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
思路来源于图解构造二叉树之中序+后序,画得图是真心棒
前提
解决此问题的关键在于要很熟悉树的各种遍历次序代表的什么,最好能够将图画出来。本题解带你先进行中序遍历和后续遍历二叉树,然后再根据遍历结果将二叉树进行还原。
首先,来一棵树
然后再看树的遍历结果
根据中序和后序遍历结果还原二叉树
中序遍历和后续遍历的特性
首先来看题目给出的两个已知条件中序遍历序列和后序遍历序列 根据这两种遍历的特性我们可以得出两个结论
如下图所示
树的还原过程描述
根据中序遍历和后续遍历的特性我们进行树的还原过程分析
树的还原过程变量定义
需要定义几个变量帮助我们进行树的还原
位置关系的计算
在找到根节点位置以后,我们要确定下一轮中,左子树和右子树在中序数组和后续数组中的左右边界的位置。
听不明白没关系,看图就对了,计算图示如下
树的还原过程
修改了原作者对变量的命名,现在小学二年级的弟弟都看懂了。
将中序遍历和后序遍历的数组抽离到类成员级别,可以有效的避免数组在多次递归中的复制操作,提升运行效率。
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
//保存中序遍历数值与下标的映射关系
Map inOrderMap = new HashMap<>();
//后序遍历数组
int[] postOrderArray;
public TreeNode buildTree(int[] inorder, int[] postorder) {
for (int i = 0; i < inorder.length; i++) {
inOrderMap.put(inorder[i], i);
}
postOrderArray = postorder;
return build(0, inorder.length - 1, 0, postorder.length - 1);
}
/**
* @param inOrderStart 中序遍历下标开始值
* @param inOrderEnd 中序遍历下标结束值
* @param postOrderStart 后序遍历下标开始值
* @param postOrderEnd 后序遍历下标结束值
* @return
*/
public TreeNode build(int inOrderStart, int inOrderEnd, int postOrderStart, int postOrderEnd) {
if (inOrderStart > inOrderEnd || postOrderStart > postOrderEnd) {
return null;
}
//获取根节点
int rootValue = postOrderArray[postOrderEnd];
//根节点在中序遍历中的索引
int rootIndex = inOrderMap.get(rootValue);
//构造根节点
TreeNode root = new TreeNode(rootValue);
root.left = build(inOrderStart, rootIndex - 1, postOrderStart, postOrderStart + rootIndex - inOrderStart - 1);
root.right = build(rootIndex + 1, inOrderEnd, postOrderStart + rootIndex - inOrderStart, postOrderEnd - 1);
return root;
}
该方案需要访问长度为n的map与数组,且节点总数目也为n,因此时间复杂度为O(n)
空间复杂度,这边使用了长度为n的map与数组,且递归的平均深度(即树的高度)小于n,因此,空间复杂度为O(n)。
提交答案: