Given two integer arrays, preorder
and postorder
where preorder
is the preorder traversal of a binary tree of distinct values and postorder
is the postorder traversal of the same tree, reconstruct and return the binary tree. If there exist multiple answers, you can return any of them.
For example:
preorder = [1,2,4,5,3,6,7], postorder = [4,5,2,6,7,3,1]
would return a binary tree that when traversed inorder, would be:
[4,2,5,1,6,3,7]
Explain your approach. Start by describing a brute force solution, then provide the optimal approach. What is the Big(O) run-time? What is the Big(O) space usage? Break down edge cases.
Given two integer arrays, preorder
and postorder
, representing the preorder and postorder traversals of a binary tree with distinct values, the task is to reconstruct and return the binary tree.
A brute-force approach would involve recursively searching for the left and right subtrees based on the given preorder and postorder arrays. We know the first element in preorder
is always the root. We find this root's position in the postorder
array. All elements before the root's position in the postorder
represent the left subtree, while the remaining elements (excluding the root) represent the right subtree. This can be done recursively.
However, this approach typically involves repeated searching within arrays, leading to a less efficient solution.
The optimal approach leverages the properties of preorder and postorder traversals using a divide-and-conquer strategy. The core idea is to recursively build the tree:
preorder
array is always the root of the current subtree.preorder
is the root of the left subtree.postorder
. This allows determining the size of the left subtree.preorder
and postorder
can be defined.Algorithm:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def construct_from_pre_post(preorder, postorder):
if not preorder or not postorder:
return None
root_val = preorder[0]
root = TreeNode(root_val)
if len(preorder) == 1:
return root
left_root_val = preorder[1]
left_root_index_in_post = postorder.index(left_root_val)
left_size = left_root_index_in_post + 1
root.left = construct_from_pre_post(
preorder[1 : 1 + left_size],
postorder[:left_size],
)
root.right = construct_from_pre_post(
preorder[1 + left_size :],
postorder[left_size:-1],
)
return root
# Example usage:
preorder = [1, 2, 4, 5, 3, 6, 7]
postorder = [4, 5, 2, 6, 7, 3, 1]
tree = construct_from_pre_post(preorder, postorder)
# A simple function to print the inorder traversal for verification
def inorder_traversal(root):
if root:
inorder_traversal(root.left)
print(root.val, end=" ")
inorder_traversal(root.right)
print("Inorder Traversal:")
inorder_traversal(tree) # Output: 4 2 5 1 6 3 7
preorder
or postorder
is empty, return None
.preorder
and postorder
arrays (e.g., different lengths, different sets of values).index()
operation in Python takes O(N) time in the worst case. However, if we use a hash map to store indices of elements in the postorder array, we can reduce the lookup time to O(1), making the overall time complexity O(N).