leetCode_105 根据一棵树的前序遍历与中序遍历构造二叉树

题目:

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

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

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

分析方法:分而治之

结合“前序遍历”和“中序遍历”的定义

前序遍历的第1个节点一定是二叉树的根节点;

中序遍历中根节点把中序遍历分成两部分,左边部分构成了二叉树的根节点的左子树,右边部分构成了二叉树根节点的右子树。

确定3为根节点,根据中序遍历,可以知道,3左边为根节点的左子树,右边为根节点的右子树;接下来进行递归...

接下来屡一下思路

假设preLeft为前序遍历的左边界,preRight为前序遍历的右边界;inLeft为中序遍历的左边界,inRight为中序遍历的右边界。

则preLeft指向的为根节点root,根节点左子树的左边界为preLeft+1,同时可以在中序遍历中找到根节点,设pIndex指向中序遍历根节点,则中序遍历中根节点左子树的区间为[inLeft,pIndex-1],右子树的区间为[pIndex+1,inRight]。剩下不知道的就是前序遍历左子树的右边界和右子树的左边界,但是其左子树长度和中序遍历长度一致,可以由如下关系获得:

最终结果如下

编写代码:

    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode(int x) {
            val = x;
        }

    }


    public static TreeNode buildTree(int[] preorder, int[] inorder) {
        int preLen = preorder.length;//前序遍历的长度
        int inLen = inorder.length;//中序遍历的长度

        // 可以不做判断,因为题目中给出的数据都是有效的
        if (preLen != inLen) {
            return null;
        }

        // 以空间换时间,否则,找根结点在中序遍历中的位置需要遍历
        Map<Integer, Integer> map = new HashMap<>(inLen);
        for (int i = 0; i < inLen; i++) {
            map.put(inorder[i], i);
        }

        return buildTree(preorder,0, preLen - 1,map, 0, inLen - 1);
    }

    /**
     * 根据前序遍历数组的 [preL, preR] 和 中序遍历数组的 [inL, inR] 重新组建二叉树
     *
     *
     * @param preorder
     * @param preL 前序遍历数组的区间左端点
     * @param preR 前序遍历数组的区间右端点
     * @param map
     * @param inL  中序遍历数组的区间左端点
     * @param inR  中序遍历数组的区间右端点
     * @return 构建的新二叉树的根结点
     */
    private static TreeNode buildTree(int[] preorder, int preL, int preR,
                                      Map<Integer, Integer> map, int inL, int inR) {
        if (preL > preR || inL > inR) {
            return null;
        }
        // 构建的新二叉树的根结点一定是前序遍历数组的第 1 个元素
        int rootVal = preorder[preL];
        TreeNode root = new TreeNode(rootVal);

        int pIndex = map.get(rootVal );//中序遍历根节点的索引

        // 按照图中描述,计算边界的取值
        root.left = buildTree(preorder, preL + 1, preL + (pIndex - inL), map, inL, pIndex - 1);
        root.right = buildTree(preorder, preL + (pIndex - inL) + 1, preR, map, pIndex + 1, inR);
        return root;
    }

至此结束!

 

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页