题目分析:
给了一个二叉树的前序遍历和后序遍历,让构建原本的二叉树,并返回其根节点
题目解析:
因为前序遍历preorder的顺序为:“根左右”,因此前序遍历的第一个数字必然为根节点root。
由题目可知此二叉树没有重复的元素,因此在中序遍历inorder的数组中可找到相同的根节点,因为中序遍历的顺序是:“左根右”,因此前面的元素都是左子树,后面的元素都是右子树。
用这种方法继续去递归深度遍历两数组,就可以得到原本的二叉树
细节优化:
中序遍历中对根节点进行定位时,一种简单的方法是直接扫描整个中序遍历的结果并找出根节点,但这样做的时间复杂度较高。我们可以考虑使用哈希表来帮助我们快速地定位根节点。对于哈希映射中的每个键值对,键表示一个元素(节点的值),值表示其在中序遍历中的出现位置。在构造二叉树的过程之前,我们可以对中序遍历的列表进行一遍扫描,就可以构造出这个哈希映射。在此后构造二叉树的过程中,我们就只需要 O(1)O(1) 的时间对根节点进行定位了。
代码实现:
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
//求得两数组长度,由题意得应该是一样的
int preLength = preorder.length;
int inLength = inorder.length;
//把后序遍历的数值和下标对应的存储到哈希表当中
Map<Integer,Integer> map = new HashMap<>(inLength);
for(int i = 0;i < inLength;i++){
map.put(inorder[i],i);
}
//递归的构建二叉树,传入前序遍历的数组和前序遍历子区间的边界,然后传入中序遍历对应关系和其子区间
return buildTree(preorder,0,preLength - 1,map,0,inLength - 1);
}
//递归函数
public TreeNode buildTree(int[] preorder,int preLeft,int preRight,Map<Integer,Integer> map,
int inLeft,int inRight){
//递归终止条件,不构成区间
if(preLeft > preRight || inLeft > inRight){
return null;
}
//前序遍历的第一个节点就是根节点
int rootVal = preorder[preLeft];
//创建根节点
TreeNode root = new TreeNode(rootVal);
//找到根节点在map上的对应位置
int pIndex = map.get(rootVal);
//继续深度遍历,向下递归
root.left = buildTree(preorder,preLeft + 1,pIndex - inLeft + preLeft,map,inLeft,pIndex - 1);
root.right = buildTree(preorder,pIndex - inLeft + preLeft + 1,preRight,map,pIndex + 1,inRight);
//返回根节点
return root;
}
}