You are given two integer arrays, preorder
and postorder
, representing the preorder and postorder traversals of a binary tree with distinct values. Your task is to reconstruct and return the binary tree.
If multiple valid binary trees can be constructed from the given traversals, you can return any one of them.
Example 1:
preorder = [1, 2, 4, 5, 3, 6, 7]
postorder = [4, 5, 2, 6, 7, 3, 1]
Construct the binary tree represented by these traversals. The output should be the root node of the constructed tree, which when traversed in-order, could yield [4,2,5,1,6,3,7]
.
Example 2:
preorder = [1]
postorder = [1]
In this case, the binary tree simply consists of a single node with the value 1. Return a TreeNode
representing this node.
Constraints:
preorder
and postorder
are between 1 and 30, inclusive.preorder
and postorder
are unique and within the range of 1 to the length of the arrays.postorder.length == preorder.length
Write a function that takes the preorder
and postorder
arrays as input and returns the root node of the reconstructed binary tree.
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The core idea of the brute force method is to explore every possible tree structure that could be formed using the given orderings. We build trees and check if they satisfy the given pre-order and post-order traversals. It is like trying all the different puzzle piece combinations until one fits.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, value):
self.value = value
self.left = None
self.right = None
def construct_binary_tree_brute_force(
preorder_traversal, postorder_traversal
):
def build_tree(
preorder_start,
preorder_end,
postorder_start,
postorder_end,
):
if preorder_start > preorder_end:
return None
root_value = preorder_traversal[preorder_start]
root = TreeNode(root_value)
# Base case: single node
if preorder_start == preorder_end:
return root
# Find the index of the left subtree root in postorder
left_subtree_root_value =
preorder_traversal[preorder_start + 1]
left_subtree_root_index =
postorder_traversal.index(left_subtree_root_value)
left_subtree_size =
left_subtree_root_index - postorder_start + 1
root.left = build_tree(
preorder_start + 1,
preorder_start + left_subtree_size,
postorder_start,
left_subtree_root_index,
)
root.right = build_tree(
preorder_start + left_subtree_size + 1,
preorder_end,
left_subtree_root_index + 1,
postorder_end - 1,
)
return root
def check_traversal(root, preorder, postorder):
preorder_result = []
postorder_result = []
def traverse(node):
if not node:
return
preorder_result.append(node.value)
traverse(node.left)
traverse(node.right)
postorder_result.append(node.value)
traverse(root)
# Postorder is constructed backwards, must reverse
postorder_result.reverse()
if preorder_result == preorder and \
postorder_result == postorder:
return True
else:
return False
trees = []
root = build_tree(0, len(preorder_traversal) - 1, 0, \
len(postorder_traversal) - 1)
# Verify if the constructed tree matches the given traversals
if check_traversal(root, preorder_traversal, \
postorder_traversal):
return root
else:
return None
# Example Usage:
# preorder = [1, 2, 4, 5, 3, 6, 7]
# postorder = [4, 5, 2, 6, 7, 3, 1]
# tree = construct_binary_tree_brute_force(preorder, postorder)
# print(tree)
We're given two ways to walk through a tree and need to rebuild the tree structure. The trick is to use the order of these walks to figure out the 'who's in charge' relationship between different parts of the tree, and then build the tree piece by piece using that knowledge.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, value=0, left=None, right=None):
self.value = value
self.left = left
self.right = right
def construct_from_preorder_postorder(preorder, postorder):
preorder_index_tracker = 0
def construct_tree(preorder_start, preorder_end, postorder_start, postorder_end):
nonlocal preorder_index_tracker
# If subarray is empty, there is nothing to construct
if preorder_start > preorder_end:
return None
# First element of preorder is root of (sub)tree
root_value = preorder[preorder_index_tracker]
root_node = TreeNode(root_value)
preorder_index_tracker += 1
# If the (sub)tree has one element, return it
if preorder_start == preorder_end:
return root_node
# Find root in postorder to determine left subtree size
left_subtree_root_index_in_postorder = postorder.index(preorder[preorder_index_tracker])
# Size of left subtree
nodes_in_left_subtree = left_subtree_root_index_in_postorder - postorder_start + 1
# Construct the left subtree
root_node.left = construct_tree(
preorder_index_tracker, preorder_index_tracker + nodes_in_left_subtree - 1,
postorder_start, left_subtree_root_index_in_postorder
)
#Advance preorder index for right subtree construction
preorder_index_tracker += nodes_in_left_subtree
# Construct the right subtree
root_node.right = construct_tree(
preorder_index_tracker, preorder_end,
left_subtree_root_index_in_postorder + 1, postorder_end - 1
)
# Return the constructed tree
return root_node
#Driver Function
root = construct_tree(0, len(preorder) - 1, 0, len(postorder) - 1)
return root
Case | How to Handle |
---|---|
Empty preorder or postorder array | Return null, as an empty tree cannot be constructed. |
Preorder and postorder arrays have different lengths | Throw an exception because a valid tree cannot be constructed from inconsistent traversals. |
Preorder and postorder arrays contain different sets of values | Throw an exception as the tree structure cannot be consistent with both traversals. |
Single element arrays | Create a single-node tree with the element as the root. |
Arrays with two elements | Create a root node with the first element of preorder, and a left child with the second element (preorder[1] must equal postorder[0]). |
All elements in the arrays are identical | The resulting tree will be a skewed tree, handled correctly by the recursive construction. |
Large input arrays potentially leading to stack overflow due to deep recursion | Ensure your code is tail-recursive or consider transforming the recursive algorithm into an iterative one. |
The given preorder and postorder traversals do not represent a valid binary tree | Return null (or throw an exception) if at any point the construction process violates the properties of preorder/postorder traversal. |