zoukankan      html  css  js  c++  java
  • [LeetCode 105] Construct Binary Tree from Preorder and Inorder Traversal

    Given preorder and inorder traversal of a tree, construct the binary tree.

    You may assume that duplicates do not exist in the tree.

    Example

    Given in-order [1,2,3] and pre-order [2,1,3], return a tree:

      2
     / 
    1   3


    Use a better example:
    preorder [1, 2, 4, 3, 5, 6]
    inorder [2, 4, 1, 5, 3, 6]

    The first node 1 of preorder is always the root node. Since there is no duplicates
    in the tree, we can uniquely find this root node 1 from inorder. The inorder is
    divided into two parts [2, 4] and [5, 3, 6] by this root node 1. Intuitively, we
    should use a recursive approach to solve a smaller problem [2, 4] and [5, 3, 6],
    then assign the root of [2, 4] as 1's left child node, the root of [5, 3, 6] as
    1's right child node.

    Dividing the inorder array is trivial, the tricky part of this problem is to divide
    the preorder array in corresponde with how we divide the inorder array.

    Let pre_start, pre_end be the start and end indices of preorder; in_start, in_end be
    the start and end indices of inorder. root_idx is the index of root in inorder.

    Left child subproblem:
    inorder new range: [in_start, root_idx - 1]
    preorder new range: [pre_start + 1, pre_start + (root_idx - in_start)]

    Right child subproblem:
    inorder new range: [root_idx + 1, in_end]
    preorder new range: [pre_end - (in_end - root_idx) + 1, pre_end]

    Base case of this recursion is when in_start > in_end, return null;

    Runtime: O(n^2)
    We need to create n nodes; For each node, we also need to do a linear search in the
    inorder array search range to find the root index. This search takes O(n) in the worst case.
    So, the upper bound is O(n^2).
    A worst case example: preorder: [1, 2, 3, 4, 5]; inorder: [5, 4, 3, 2, 1]


     1 /**
     2  * Definition of TreeNode:
     3  * public class TreeNode {
     4  *     public int val;
     5  *     public TreeNode left, right;
     6  *     public TreeNode(int val) {
     7  *         this.val = val;
     8  *         this.left = this.right = null;
     9  *     }
    10  * }
    11  */
    12 public class Solution {
    13     /**
    14      *@param preorder : A list of integers that preorder traversal of a tree
    15      *@param inorder : A list of integers that inorder traversal of a tree
    16      *@return : Root of a tree
    17      */
    18     public TreeNode buildTree(int[] preorder, int[] inorder) {
    19         if(preorder.length != inorder.length){
    20             return null;
    21         }
    22         return buildTreeRecursive(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
    23     }
    24     private int findPosition(int[] arr, int start, int end, int target){
    25         for(int i = start; i <= end; i++){
    26             if(arr[i] == target){
    27                 return i;
    28             }
    29         }
    30         return -1;
    31     }
    32     private TreeNode buildTreeRecursive(int[] preorder, int pre_start, int pre_end, 
    33                                int[] inorder, int in_start, int in_end){
    34         if(in_start > in_end){
    35             return null;
    36         }
    37         TreeNode root = new TreeNode(preorder[pre_start]);
    38         int position = findPosition(inorder, in_start, in_end, preorder[pre_start]);
    39         
    40         root.left = buildTreeRecursive(preorder, pre_start + 1, pre_start + position - in_start,
    41                                        inorder, in_start, position - 1);
    42         root.right = buildTreeRecursive(preorder, pre_end - (in_end - position) + 1, pre_end,
    43                                         inorder, position + 1, in_end);
    44         return root;
    45     }
    46 }


    Optimization: Instead of searching for the current in order root in linear time, we can preprocess the in order indices and save them in a hash map
    so that it takes O(1) time to find the next recursion range on both pre order and in order. This way, the runtimes becomes O(N).

    The key here is that we use the current in order range and root index to compute the next recursion range for pre order.


    class Solution {
        public TreeNode buildTree(int[] preorder, int[] inorder) {
            Map<Integer, Integer> idxMap = new HashMap<>();
            for(int i = 0; i < inorder.length; i++) {
                idxMap.put(inorder[i], i);
            }
            return helper(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1, idxMap);
        }
        private TreeNode helper(int[] preorder, int preStart, int preEnd, 
                                int[] inorder, int inStart, int inEnd,
                                Map<Integer, Integer> idxMap) {
            if(preStart > preEnd || inStart > inEnd) {
                return null;
            }
            TreeNode root = new TreeNode(preorder[preStart]);
            int splitIdx = idxMap.get(preorder[preStart]);
            int leftCount = splitIdx - inStart;
            root.left = helper(preorder, preStart + 1, preStart + leftCount, inorder, splitIdx - leftCount, splitIdx - 1,idxMap);
            root.right = helper(preorder, preStart + leftCount + 1, preEnd, inorder, splitIdx + 1, inEnd, idxMap);
            return root;
        }
    }
     




    Related Problems
    Construct Binary Tree from Inorder and Postorder Traversal
    Construct Binary Tree from Inorder and Levelorder Traversal
    Binary Tree Serialization
  • 相关阅读:
    【XSY2720】区间第k小 整体二分 可持久化线段树
    【XSY2719】prime 莫比乌斯反演
    【XSY2718】gift 分数规划 网络流
    【CTSC2017】【BZOJ4903】吉夫特 卢卡斯定理 DP
    【XSY2729】欧拉子图 无向图连通性 数学
    【XSY2730】Ball 多项式exp 多项式ln 多项式开根 常系数线性递推 DP
    【BZOJ1999】【NOIP2007】树网的核 单调队列优化DP
    NOIP2017游记
    【BZOJ2127】happiness 网络流
    【BZOJ3625】【CF438E】小朋友和二叉树 NTT 生成函数 多项式开根 多项式求逆
  • 原文地址:https://www.cnblogs.com/lz87/p/7043388.html
Copyright © 2011-2022 走看看