<leetcode> 105. Construct Binary Tree from Preorder and Inorder Traversal 重建二叉树

Note:《剑指offer》面试题7 重建二叉树
题目:给出了前序和中序周游序列,根据这两个序列重建一棵二叉树
关键点:前序周游时,根节点为序列的第一个值;中序周游时,根节点左边的序列是根节点的左子树节点,右边是右子树节点



第1、2种方法思路一致,只不过用了Map以提高检索父节点和子节点index的效率。
思路:遍历除了第一个值的前序周游子序列,将所有其他值和根节点值对比,通过在中序周游序列中它们的index判断(节点index先于根节点index,则为其左子树,反之右子树,这个判断由中序周游的特点决定的)。节点在根节点在其左子树或右子树,如果根节点没有左儿子或者右儿子节点,则该节点成为其子节点;否则,节点将要对比的新根节点变成原根节点的儿子节点,直到它成为某个对比的根节点的子节点。 时间复杂度应该是O(n*h),n为节点数,h为树的高度。

第一种方法,超时因为indexOf

public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder == null || preorder.length == 0){
            return null;
        }
        TreeNode root = new TreeNode(preorder[0]);
        TreeNode parent = root;
        // 从先序周游开始
        for(int i = 1; i < preorder.length; i++){
            TreeNode node = new TreeNode(preorder[i]);
            while(true){
                boolean isLeft = isLeftSubTree(inorder, parent.val, node.val);
                if(isLeft){ // 如果是左子树
                    if(parent.left == null){ // 左子树为空,则它为父节点的左儿子
                        parent.left = node;
                        break;
                    }else{   // 左子树有自己的根节点,则将和其对比
                        parent = parent.left;
                    }
                }else{
                    if(parent.right == null){
                        parent.right = node;
                        break;
                    }else{
                        parent = parent.right;
                    }
                }
            }
            parent = root;
        }
        return root;
    }
/** 节点是root节点的左子树还是右子树 **/
    private boolean isLeftSubTree(int[] inorder, int root, int node) {
        int rootIndex = indexOf(inorder, root);
        int nodeIndex = indexOf(inorder, node);
        // 如果节点在中序周游的索引位于根节点的后面,表示它在根节点的右子树
        if(nodeIndex > rootIndex){
            return false;
        }else if(nodeIndex < rootIndex){ // 反之
            return true;
        }else{
            return false;
        } // 按理来说不存在
    }

    /** 找到某数在数组中的索引 **/
    private int indexOf(int[] array, int elem){
        for (int i = 0; i < array.length; i++) {
            if (elem == array[i])
                return i;
        }
        return -1;
    }      

第二种方法,103ms

public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder == null || preorder.length == 0){
            return null;
        }
        TreeNode root = new TreeNode(preorder[0]);
        TreeNode parent = root;
        Map<Integer, Integer> inorderIndexMap = buildIndexMap(inorder);
        // 从先序周游开始
        for(int i = 1; i < preorder.length; i++){
            TreeNode node = new TreeNode(preorder[i]);
            while(true){
                boolean isLeft = isLeftSubTree(inorderIndexMap, parent.val, node.val);
                if(isLeft){
                    if(parent.left == null){
                        parent.left = node;
                        break;
                    }
                    else{
                        parent = parent.left;
                    }
                }else{
                    if(parent.right == null){
                        parent.right = node;
                        break;
                    }
                    else{
                        parent = parent.right;
                    }
                }
            }
            parent = root;
        }
        return root;
    }

    private boolean isLeftSubTree(Map<Integer, Integer> inorderIndexMap, int root, int node) {
        int rootIndex = inorderIndexMap.get(root);
        int nodeIndex = inorderIndexMap.get(node);
        // 如果节点在中序周游的索引位于根节点的后面,表示它在根节点的右子树
        if(nodeIndex > rootIndex){
            return false;
        }else if(nodeIndex < rootIndex){ // 反之
            return true;
        }else{
            return false;
        } // 按理来说不存在
    }

    /** 用不重复的数组建其值与index的map **/
    private Map<Integer, Integer> buildIndexMap(int[] array){
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        int index = 0;
        for(int x : array){
            map.put(x, index);
            index++;
        }
        return map;
    }



第3种,方法看了《剑指offer》面试题7——重建二叉树的思路后实现的
思路:在树的前序遍历中,根节点为第一个,后面连续的一部分子序列为左子树节点,左子树序列后面连续的子序列为右子树节点。在中序遍历中,根节点以左序列为根节点的左子树,以右序列为右子树节点。那么,在前序周游序列中得到根节点值,可以通过该值在中序周游序列中找到其index,那么index之前为左子树,通过计算能得到左右子树节点数。然后,重建左右子树,用递归的方法重建整个二叉树。 时间复杂度O(n)

第三种方法,6ms

private Map<Integer, Integer> inorderIndexMap = null;

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder == null || preorder.length == 0){
            return null;
        }
        inorderIndexMap = buildIndexMap(inorder);
        return buildTree(preorder.length, preorder, 0, inorder, 0);
    }

    private TreeNode buildTree(int len, int[] preorder, int pStart,
                               int[] inorder, int iStart) {

        if(len <= 0){
            return null;
        }
        TreeNode root = new TreeNode(preorder[pStart]); // 在preorder中第pStart个为子树的root
        int rootIndex = inorderIndexMap.get(root.val); //找到inorder中子树root的位置
        int leftLen = rootIndex-iStart;
        root.left = buildTree(leftLen, preorder, pStart+1, inorder, iStart);
        root.right = buildTree(len-1-leftLen, preorder, pStart+1+leftLen, inorder, rootIndex+1);
        return root;
    }


    /** 用不重复的数组建其值与index的map **/
    private Map<Integer, Integer> buildIndexMap(int[] array){
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        int index = 0;
        for(int x : array){
            map.put(x, index);
            index++;
        }
        return map;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值