Construct Binary Tree from Preorder and Inorder Traversal⚓︎
Description⚓︎
Given two integer arrays preorder
and inorder
where preorder
is the preorder traversal of a binary tree and inorder
is the inorder traversal of the same tree, construct and return the binary tree.
Example 1:
- Input:
preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
- Output:
[3,9,20,null,null,15,7]
Example 2:
- Input:
preorder = [-1], inorder = [-1]
- Output:
[-1]
Constraints:
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder
andinorder
consist of unique values.- Each value of
inorder
also appears inpreorder
. preorder
is guaranteed to be the preorder traversal of the tree.inorder
is guaranteed to be the inorder traversal of the tree.
Solution⚓︎
- First, use pre-order traversal to find the root node: the first number in the pre-order traversal is the value of the root node;
- Find the position of the root node in the in-order traversal,
pos
. Then, the left side ofpos
is the in-order traversal of the left subtree, and the right side is the in-order traversal of the right subtree; - Assume that the length of the in-order traversal of the left subtree is
index
. Then, in the pre-order traversal, theindex
numbers following the root node are the pre-order traversal of the left subtree, and the remaining numbers are the pre-order traversal of the right subtree; - With the pre-order and in-order traversals of the left and right subtrees, we can first recursively create the root node, then recursively create the left and right subtrees, and finally attach these two subtrees to the left and right positions of the root node.
Illustration:
Code:
Code with comments:
Explanation of Algorithm:
The algorithm uses recursion to construct the binary tree. It leverages the property that the first element of a preorder traversal is always the root of the tree, and then finds this root's index in the inorder traversal to divide the tree into left and right subtrees.
- Initializing Hash Map: The
unordered_map
namedpos
maps each value in the inorder traversal to its index. This speeds up the search operation which is required to find the root node in the inorder sequence. - Recursive Tree Construction: The
treeBuilder
function is the core of the algorithm. It takes the current interval of preorder and inorder traversals to construct the tree. The first element of the current preorder interval is the root. The function then finds this root in the inorder interval, which divides the tree into left and right subtrees. The left and right child nodes are then recursively constructed. - Interval Changes in Recursion: The preorder and inorder intervals are updated in each recursive call to reflect the current subtree being constructed. The index found in the inorder traversal helps in determining the size of the left and right subtrees, which is then used to update the intervals.
Time and Space Complexity Analysis:
- Time Complexity: \(O(n)\)
- The hash map reduces the search operation for the root in the inorder traversal to \(O(1)\).
- Each node is visited exactly once, leading to a linear time complexity.
- Space Complexity: \(O(n)\)
- The space for the hash map, which contains \(n\) elements.
- The recursive stack space, which, in the worst case, can go up to \(O(n)\) in the case of a skewed tree.
Additional Notes:
Constructing the Left Subtree:
In this line, the algorithm is constructing the left subtree of the current root node. Here's how it works:
- Finding the Root of the Left Subtree:
preorderLeft + 1
: The left child of the current root in the preorder sequence is always the next element (preorderLeft + 1
).
- Determining the Bounds of the Left Subtree:
preorderLeft + index - inorderLeft
: This expression calculates the right bound of the left subtree in the preorder sequence.index
is the position of the current root in the inorder sequence.inorderLeft
is the left bound of the inorder sequence for the current subtree.- The difference
index - inorderLeft
gives the size of the left subtree. Adding this topreorderLeft
(and adjusting by 1 for the root) sets the right boundary in the preorder sequence.
- Setting the Inorder Interval:
inorderLeft, index - 1
: In the inorder sequence, the left subtree is always to the left of the root. So, the left subtree spans frominorderLeft
toindex - 1
(one element before the root).
Constructing the Right Subtree:
In this line, the algorithm constructs the right subtree:
- Finding the Root of the Right Subtree:
preorderLeft + index - inorderLeft + 1
: This expression finds the starting point of the right subtree in the preorder sequence. The logic is similar to the left subtree, but it includes an additional+1
to skip over the entire left subtree.
- Determining the Bounds of the Right Subtree:
preorderRight
: The right boundary in the preorder sequence remains the same as the parent's right boundary, as we are now dealing with the right subtree.
- Setting the Inorder Interval:
index + 1, inorderRight
: In the inorder sequence, the right subtree is always to the right of the root. Therefore, the interval for the right subtree starts fromindex + 1
(one element after the root) toinorderRight
.