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
  • 相关阅读:
    C# 之委托
    Java Maven安装及配置,利用Maven创建项目
    Java DecimalFormat四舍五入的坑及正确用法
    Java 解析XML的几种方式:DOM、SAX、JDOM和DOM4J。
    Java Properties配置文件和XML配置文件读取
    Java Map一些基本使用方法
    JAVA for循环的几种用法
    鼠标及键盘操作
    控制浏览器
    元素定位
  • 原文地址:https://www.cnblogs.com/lz87/p/7043388.html
Copyright © 2011-2022 走看看