105. Construct Binary Tree from Preorder and Inorder Traversal#
Difficulty: Medium
Link to Problem: To see the Construct Binary Tree from Preorder and Inorder Traversal problem on LeetCode, click here!
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.
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:#
Here’s a Python function to solve this problem:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def buildTree(preorder, inorder):
if not preorder:
return None
# The first element in the preorder traversal is the root of the current subtree
root_val = preorder[0]
root = TreeNode(root_val)
# Find the index of the root value in the inorder traversal
root_idx_inorder = inorder.index(root_val)
# Recursively build left and right subtrees
root.left = buildTree(preorder[1:1 + root_idx_inorder], inorder[:root_idx_inorder])
root.right = buildTree(preorder[1 + root_idx_inorder:], inorder[root_idx_inorder + 1:])
return root
Explanation:#
class TreeNode:
: This is a class definition for a binary tree node. It has three attributes:val
: The value of the node.left
: A reference to the left child node.right
: A reference to the right child node.
This class is used to create instances of binary tree nodes, which will be used to build the binary tree.
def buildTree(preorder, inorder):
: This is the main function that constructs a binary tree from its preorder and inorder traversals.preorder
: A list representing the preorder traversal of the binary tree.inorder
: A list representing the inorder traversal of the binary tree.
if not preorder: return None
: This line checks if thepreorder
list is empty. If it is, it means there are no nodes to construct, so the function returnsNone
.root_val = preorder[0]
: The value of the root node is extracted from the first element of thepreorder
list.root = TreeNode(root_val)
: A newTreeNode
object is created with theroot_val
as its value. This represents the root of the current subtree.root_idx_inorder = inorder.index(root_val)
: The index of theroot_val
in theinorder
list is found. This index indicates the position of the root node in the inorder traversal.root.left
: The left subtree is constructed recursively by calling thebuildTree
function with the appropriate sublists ofpreorder
andinorder
. The left subtree’s preorder and inorder traversals are the slices ofpreorder
andinorder
lists up to theroot_idx_inorder
.root.right
: The right subtree is constructed recursively by calling thebuildTree
function with the appropriate sublists ofpreorder
andinorder
. The right subtree’s preorder and inorder traversals are the slices ofpreorder
andinorder
lists starting fromroot_idx_inorder + 1
.Finally, the function returns the
root
of the subtree it just constructed.
The recursive approach used here divides the problem of constructing the entire binary tree into smaller subproblems, starting with the root node and then recursively building the left and right subtrees until the entire tree is constructed.
Helper Function#
Here is a helper function to represent the binary tree elements.
def treeToList(root):
# Initialize an empty list to store the elements of the binary tree
result = []
# Initialize a queue for level-order traversal starting with the root
queue = [root]
while queue:
# Pop the front node from the queue
node = queue.pop(0)
# If the node is not None (i.e., a valid node), add its value to the result list
if node:
result.append(node.val)
# Add the left and right children of the node to the queue
queue.append(node.left)
queue.append(node.right)
else:
# If the node is None, add None to the result to represent an empty node
result.append(None)
# Remove any trailing None values from the result list
while result and result[-1] is None:
result.pop()
# Return the resulting list representing the binary tree elements
return result
Explanation:#
Let’s break down the treeToList
helper function step by step:
def treeToList(root):
: This function takes the root of a binary tree as input and converts it into a list.result = []
: Initialize an empty list calledresult
to store the elements of the binary tree in list format.queue = [root]
: Initialize a queue data structure for a level-order traversal, starting with the root node.while queue:
: This starts a loop that continues until the queue is empty, indicating that all nodes have been processed.node = queue.pop(0)
: Dequeue the first node from the queue, effectively processing it.if node:
: Check if thenode
is not None, which means it’s a valid node in the binary tree.a.
result.append(node.val)
: If the node is valid, append its value (node.val
) to theresult
list. This represents the value of the current node in the binary tree.b.
queue.append(node.left)
: Enqueue the left child of the current node if it exists. This adds the left child to the queue for processing in the next iteration.c.
queue.append(node.right)
: Enqueue the right child of the current node if it exists. This adds the right child to the queue for processing in the next iteration.else:
: If thenode
is None, it represents an empty node in the binary tree.a.
result.append(None)
: AppendNone
to theresult
list to indicate an empty node.while result and result[-1] is None:
: After the traversal is complete, there might be trailingNone
values in theresult
list. This loop removes any such trailingNone
values to ensure a clean representation of the tree’s elements.return result
: Return theresult
list, which now contains the elements of the binary tree in a format whereNone
represents empty nodes and the order of elements reflects a level-order traversal of the tree.
In summary, the treeToList
function performs a level-order traversal of the binary tree using a queue, constructing a list where each element corresponds to a node’s value or represents an empty node with None
. This list represents the binary tree’s elements in a structured format.
Test cases#
# Example 1:
# Example usage:
preorder = [3, 9, 20, 15, 7]
inorder = [9, 3, 15, 20, 7]
result = buildTree(preorder, inorder)
print(treeToList(result))
[3, 9, 20, None, None, 15, 7]
# Example 2:
preorder = [-1]
inorder = [-1]
result = buildTree(preorder, inorder)
print(treeToList(result))
[-1]
Time and Space Complexity Analysis#
Let’s analyze the time and space complexity of the buildTree
function:
Time Complexity:
The time complexity of the buildTree
function can be analyzed in terms of the number of nodes in the binary tree. Let’s assume there are n
nodes in the binary tree.
Finding the root value in the
preorder
traversal takes O(1) time as it’s just extracting the first element from the list.Finding the index of the root value in the
inorder
traversal usinginorder.index(root_val)
takes O(n) time in the worst case because in the worst case, it might have to search through alln
elements in theinorder
list to find the index.The recursive calls to
buildTree
for the left and right subtrees are made once for each node in the tree. Therefore, the recursive calls have a combined time complexity of O(n) as they process each node once.
The total time complexity of the buildTree
function is O(n) due to the recursive calls and finding the root’s index in the inorder
list.
Space Complexity: The space complexity is determined by the space used by the function’s call stack during recursion and any additional data structures used.
The space used by the function call stack during recursion depends on the height of the binary tree. In the worst case, where the tree is highly unbalanced (e.g., a skewed tree), the space complexity for the call stack is O(n) as it can go as deep as the number of nodes in the tree.
Additionally, the function creates TreeNode objects for each node in the binary tree. Therefore, the space complexity for these objects is also O(n).
Overall, the space complexity of the buildTree
function is O(n) due to the space used by the call stack and the TreeNode objects.
In summary, the time complexity of buildTree
is O(n), and the space complexity is O(n), where ‘n’ is the number of nodes in the binary tree.
Challenging Exercises:#
Construct Binary Tree from Postorder and Inorder Traversal: Modify the problem to construct a binary tree from its postorder and inorder traversals. Implement a function similar to
buildTree
but for postorder and inorder traversals.Reconstruct Binary Tree with Duplicate Values: Extend the problem to handle binary trees with duplicate values. Ensure that your solution correctly handles scenarios where there are duplicate values in the preorder and inorder traversals.