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

题目:

思路:

【1】可以借鉴  剑指 Offer 07. 重建二叉树(105. 从前序与中序遍历序列构造二叉树) 这一篇,因为本质思路都是一样的。

【2】常规模拟分割的方式

代码展示:

【1】常规模拟分割的方式(这种方式通俗易懂,是将大树构建的方式划分为了小树的构建然后组合成大树,由于划分的时候需要每次都获取中序遍历的位置,所以一开始采用了一次遍历并将数据存于hashMap中便于查找来避免了每次需要遍历获取下标这一步)

//时间2 ms 击败 48.96%
//内存42.4 MB 击败 23.24%
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    private Map<Integer, Integer> indexMap;

    /**
     * 将两个序列复原出一个树
     * @param inorder 中序遍历(左中右)
     * @param postorder 后序遍历(左右中)
     * @return
     */
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        int n = inorder.length;
        // 构造哈希映射,帮助我们快速定位根节点
        indexMap = new HashMap<Integer, Integer>();
        for (int i = 0; i < n; i++) {
            indexMap.put(inorder[i], i);
        }
        return myBuildTree(postorder, inorder, 0, n - 1, 0, n - 1);
    }

    public TreeNode myBuildTree(int[] postorder, int[] inorder, int postorder_left, int postorder_right, int inorder_left, int inorder_right) {
        if (postorder_left > postorder_right)  return null;

        // 后序遍历中的最后一个节点就是根节点
        int preorder_root = postorder_right;
        // 在中序遍历中定位根节点
        int inorder_root = indexMap.get(postorder[preorder_root]);

        // 先把根节点建立出来
        TreeNode root = new TreeNode(postorder[preorder_root]);
        // 得到左子树中的节点数目
        int size_left_subtree = inorder_root - inorder_left;
        // 得到右子树中的节点数目
        int size_right_subtree = inorder_right - inorder_root;

        // 递归地构造左子树,并连接到根节点
        // 后序遍历中「从 左边界 开始的 size_left_subtree - 1」个元素(因为 左边界 + size_left_subtree = 刚好到目标位置多走了一步)
        // 就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
        root.left = myBuildTree(postorder, inorder, postorder_left , postorder_left + size_left_subtree - 1 , inorder_left, inorder_root - 1);

        // 递归地构造右子树,并连接到根节点
        // 后序遍历中「从 左边界+左子树节点数目 开始到 右边界 - 1」的元素(因为最后的那个元素已经拿出来作为根节点了)
        // 就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
        root.right = myBuildTree(postorder, inorder, postorder_left + size_left_subtree, postorder_right - 1, inorder_root + 1, inorder_right);

        return root;
    }
}

【2】进行比对的部分(原本想着Map直接获取吧应该会比较快,然而实际上,缩短遍历范围的遍历,远比在map中查找获取更快,难道是因为是map内部获取的操作其实远远复杂于遍历查找的过程?)

//时间0 ms 击败 100%
//内存42.3 MB 击败 33.4%
class Solution {
    int i;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        i = postorder.length-1;
        return build(inorder,postorder,0,inorder.length-1);
    }
    TreeNode build(int[] inorder,int[] postorder,int inBegin,int inEnd){
        if(inBegin>inEnd){
            return null;
        }
        TreeNode root = new TreeNode(postorder[i]);
        int rootIndex = find(inorder,inBegin,inEnd,root.val);
        i--;
        root.right = build(inorder,postorder,rootIndex+1,inEnd);
        root.left = build(inorder,postorder,inBegin,rootIndex-1);
        return root;
    }
    int find(int[] inorder,int inBegin,int inEnd,int val){
        for(int j=inEnd;j>=inBegin;j--){
            if(inorder[j]==val){
                return j;
            }
        }
        return -1;
    }
}

//时间2 ms 击败 48.96%
//内存42.2 MB 击败 42.57%
class Solution {
    private Map<Integer, Integer> indexMap;
    int i;
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        i = postorder.length-1;
        // 构造哈希映射,帮助我们快速定位根节点
        indexMap = new HashMap<Integer, Integer>();
        for (int i = 0; i < inorder.length; i++) {
            indexMap.put(inorder[i], i);
        }
        return build(inorder,postorder,0,inorder.length-1);
    }

    private TreeNode build(int[] inorder,int[] postorder,int inBegin,int inEnd){
        if(inBegin>inEnd){
            return null;
        }
        TreeNode root = new TreeNode(postorder[i]);
        int rootIndex = indexMap.get(postorder[i]);
        i--;
        root.right = build(inorder,postorder,rootIndex+1,inEnd);
        root.left = build(inorder,postorder,inBegin,rootIndex-1);
        return root;
    }
}

 

posted @ 2023-07-07 15:52  忧愁的chafry  阅读(10)  评论(0编辑  收藏  举报