[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