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
  • 相关阅读:
    Java实现 LeetCode 324 摆动排序 II
    Java实现 LeetCode 324 摆动排序 II
    ubuntu 10.10配置NFS网络共享步骤
    让C/C++程序一次编译可以发布到多版本Linux之上
    linux下so动态库一些不为人知的秘密(中二)
    linux下so动态库一些不为人知的秘密(中)
    linux下so动态库一些不为人知的秘密(上)
    tftp使用方法
    Linux操作系统下三种配置环境变量的方法
    Linux中环境变量文件及配置
  • 原文地址:https://www.cnblogs.com/lz87/p/7043388.html
Copyright © 2011-2022 走看看