题目描述
输入一棵二叉树前序遍历和中序遍历的结果,请重建该二叉树。
注意:
二叉树中每个节点的值都互不相同;
输入的前序遍历和中序遍历一定合法;
样例描述
给定:
前序遍历是:[3, 9, 20, 15, 7]
中序遍历是:[9, 3, 15, 20, 7]
返回:[3, 9, 20, null, null, 15, 7, null, null, null, null]
返回的二叉树如下所示:
3
/ \
9 20
/ \
15 7
/**
* Definition for a binary tree node.
* class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
思路
- 由前序序列和中序序列的特点,前序总是先出现根结点,再是左右子树结点。而该根结点在中序中的位置,可以将中序分成左右两个子树。
- 因此可以用递归,start为当前中序中的最左边的下标,end为当前中序中最右边的下标。root为前序中当前的根结点下标(把一棵树分为左子树和右子树)。
- 为了方便找到前序根结点在中序的位置,先用hashMap存储所有结点和他的在中序中的下标作为一对键值对。
- 递归创建左右子树,注意这里参数容易写错,
root+1
为中序中左子树的根结点。i-start+1
为中序中根结点的左边结点的个数(即左子树的个数),因此root+i-start+1
为中序右子树中根结点的下标。然后进行左右子区间的递归创建左右子树就行。 这里采用的是后序建树,即左右根的顺序。
代码
class Solution {
//存储结点在中序中的下标
HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n=preorder.length;
for(int i=0;i<n;i++){
map.put(inorder[i],i);
}
return dfs(preorder,inorder,0,0,n-1);
}
//start为当前中序中的最左边的下标,end为当前中序中最右边的下标。
//root为前序中当前的根结点下标(把一棵树分为左子树和右子树)
private TreeNode dfs(int []pre,int []in,int root,int start,int end){
if(start>end) return null;
//找到根结点在中序中的位置
int i=map.get(pre[root]);
TreeNode tree=new TreeNode(pre.length);
//后序建树,左右根
tree.left=dfs(pre,in,root+1,start,i-1);
tree.right=dfs(pre,in,root+i-start+1,i+1,end);
tree.val=pre[root];
return tree;
}
}