题目描述
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
解法一:递归+哈希
- 先将inorder存入哈希表中,方便查找
- 调用创建二叉树函数
- 利用preorder设置根节点,在inorder找到根节点,区分左右子树
- 找出左右子树的起点终点
- 分别调用左右子树
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n=preorder.length,m=inorder.length;
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<n;i++){
map.put(inorder[i],i);
}
return buildTreeHelper(preorder,0,n-1,inorder,0,m-1,map);
}
public TreeNode buildTreeHelper(int[] preorder,int p_start,int p_end,int[] inorder,int i_start,int i_end,Map<Integer,Integer> map){
//终止条件
if(p_start>p_end||i_start>i_end){
return null;
}
//创建根节点
int root_val=preorder[p_start];
TreeNode root=new TreeNode(root_val);
//找出inorder的根所在位置,用于区分左右子树
int root_index=map.get(root_val);
//用len记录左子树长度
int len=root_index-i_start;
//pre 起点+1为新起点,起点+len为终点
//in 起点不变,终点为根位置-1
root.left=buildTreeHelper(preorder,p_start+1,p_start+len,inorder,i_start,root_index-1,map);
//pre 起点为(起点+len)+1 终点不变
//in 起点为根位置+1,终点不变
root.right=buildTreeHelper(preorder,p_start+len+1, p_end,inorder,root_index+1,p_end,map);
return root;
}
}
解法二:全递归+先序遍历
- 终止条件1:preorder数组内的数字均已构造
- 终止条件2:中序到达终止点stop,终点+1为新起点,返回null
- 过程:利用先序遍历构造树。
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildTreeHelper(preorder,inorder,Integer.MAX_VALUE);
}
//当前要构造的树的根节点
int pre=0;
//当前构造的树的开头
int in=0;
public TreeNode buildTreeHelper(int[] preorder,int[] inorder,int stop){
//终止条件
if(pre==preorder.length){
return null;
}
//子树终点,当前停止点已经使用过,in后移
//in到stop为要构造的树当前的数字范围
if(inorder[in]==stop){
in++;
return null;
}
//下面四行典型先序遍历
int root_val=preorder[pre++];
TreeNode root=new TreeNode(root_val);
//左子树在当前根节点停止(in到root_val为左子树范围)
root.left=buildTreeHelper(preorder,inorder,root_val);
//右子树停止点是当前树的停止点(左子树构造后,此时新的in-stop为右子树范围)
root.right=buildTreeHelper(preorder,inorder,stop);
return root;
}
}