给定一棵树的前序遍历 preorder
与中序遍历 inorder
。请构造二叉树并返回其根节点。
一开始一个笨比写法,没什么大问题,但是效率很低,在中序遍历中想找根节点,显然使用哈希表比较好,因为从头到尾我们都维护着初始数组不变,所以可以从头到尾使用同一个哈希表
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
int[]pre=new int[]{0,preorder.length};
int[]in=new int[]{0,inorder.length};
HashMap<Integer,Integer>map=new HashMap<>();
for(int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return build(map,preorder, inorder,pre,in);
}
//pre[],in[]记载本轮遍历的下标范围
//pre[0]对应本轮子树的根
TreeNode build(HashMap<Integer,Integer>map,int[] preorder, int[] inorder,int[]pre,int[]in){
if(pre[1]==pre[0]){
return null;
}
int num=preorder[pre[0]];
TreeNode root=new TreeNode(num),left=null,right=null;
//System.out.println("中序遍历从的子树");
for(int i=in[0];i<in[1];i++){
//找到了本轮根在中序遍历的位置,
//该位置之前为左子树,右边为右子树
//2为中序遍历,1为前序遍历
if(inorder[i]==num){
//System.out.println("根节点在中序遍历的下标为"+i);
int[]pre1=new int[]{pre[0]+1,pre[0]+i-in[0]+1};
int[]in1=new int[]{in[0],i};
root.left=build(map,preorder, inorder, pre1, in1);
//System.out.println("左子树建构完成");
int[]pre2=new int[]{pre[0]+i-in[0]+1,pre[1]};
int[]in2=new int[]{i+1,in[1]};
root.right=build(map,preorder, inorder, pre2, in2);
//System.out.println("右子树建构完成");
}
}
//System.out.println("根节点为"+num+"的子树");
return root;
}
}
使用哈希表 ,速度快了很多
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
int[]pre=new int[]{0,preorder.length};
int[]in=new int[]{0,inorder.length};
HashMap<Integer,Integer>map=new HashMap<>();
for(int i=0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return build(map,preorder, inorder,pre,in);
}
//pre[],in[]记载本轮遍历的下标范围
//pre[0]对应本轮子树的根
TreeNode build(HashMap<Integer,Integer>map,int[] preorder, int[] inorder,int[]pre,int[]in){
//注意判断,如果出现这种情况,一定是越界了,证明该子树为空,立刻返回null
if(pre[1]==pre[0]){
return null;
}
int num=preorder[pre[0]];
TreeNode root=new TreeNode(num),left=null,right=null;
//System.out.println("中序遍历从的子树");
int i=map.get(num);
int[]pre1=new int[]{pre[0]+1,pre[0]+i-in[0]+1};
int[]in1=new int[]{in[0],i};
root.left=build(map,preorder, inorder, pre1, in1);
int[]pre2=new int[]{pre[0]+i-in[0]+1,pre[1]};
int[]in2=new int[]{i+1,in[1]};
root.right=build(map,preorder, inorder, pre2, in2);
return root;
}
}
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
和上一题同理,区别是pre从开头取根,post从结尾取根
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
int n=inorder.length;
int[]post=new int[]{0,n};
int[]in=new int[]{0,n};
HashMap<Integer,Integer>map=new HashMap<>();
for(int i=0;i<n;i++){
map.put(inorder[i],i);
}
return build(map, inorder, postorder, in, post);
}
TreeNode build(HashMap<Integer,Integer>map,int[] inorder, int[] postorder,
int[]in,int[]post){
if(post[0]==post[1]){
return null;
}
int val=postorder[post[1]-1];
TreeNode root=new TreeNode(val);
int i=map.get(val);
//左子树的长度
int len=i-in[0];
int[]in1=new int[]{in[0],i};
int[]post1=new int[]{post[0],post[0]+len};
root.left=build(map, inorder, postorder, in1, post1);
int[]in2=new int[]{i+1,in[1]};
int[]post2=new int[]{post[0]+len,post[1]-1};
root.right=build(map, inorder, postorder, in2, post2);
return root;
}
}