LeetCode树复习I-构造二叉树

105. 从前序与中序遍历序列构造二叉树 

给定一棵树的前序遍历 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;
    }
}

106. 从中序与后序遍历序列构造二叉树 

根据一棵树的中序遍历与后序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

和上一题同理,区别是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;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值