Skip to content

Construct Binary Tree from Inorder and Postorder Traversal

Given two integer arrays inorder and postorder where:

  • inorder is the inorder traversal of a binary tree
  • postorder is the postorder traversal of the same tree

Construct and return the binary tree.

InputExpected OutputTree Structure
inorder: [9,3,15,20,7], postorder: [9,15,7,20,3]TreeNode(3)3 with left child 9 and right subtree 20 (children: 15, 7)
inorder: [1], postorder: [1]TreeNode(1)Single node with value 1
inorder: [2,1,3], postorder: [2,3,1]TreeNode(1)1 with left child 2 and right child 3
  • 1 <= inorder.length <= 3000
  • postorder.length == inorder.length
  • -3000 <= inorder[i], postorder[i] <= 3000
  • inorder and postorder consist of unique values.
  • Each value of postorder also appears in inorder.
  • inorder is guaranteed to be the inorder traversal of the tree.
  • postorder is guaranteed to be the postorder traversal of the tree.
ApproachTimeSpaceLookupBest When
HashMap (Recommended)O(n)O(n)O(1)General case — optimal for all tree sizes
Index TrackingO(n²)O(h)O(n)Trees with minimal memory constraints (rare)
  • Pick HashMap if you want the optimal solution — it’s the standard interview approach.
  • Pick Index Tracking if you want to understand the core recursion without HashMap overhead.
Optimal For Speed
HashMap
O(n) time · O(n) space
Memory Optimized
Index Tracking
O(n²) time · O(h) space
★ Recommended

Use a HashMap to store each inorder value’s index. For each recursive step:

  1. The last element in postorder is the current root.
  2. Find the root’s position in inorder using the HashMap (O(1) lookup).
  3. Count how many nodes are in the left subtree.
  4. Recursively build the left and right subtrees using appropriate ranges.
⏱ Time O(n) Single pass with O(1) lookups 💾 Space O(n) HashMap + recursion stack

Input: inorder = [9, 3, 15, 20, 7], postorder = [9, 15, 7, 20, 3]

StepPostorder RangePostorder[end]Inorder PositionLeft SubtreeRight Subtree
1[9,15,7,20,3]3 (root)index 1[9] at left[15,20,7] at right
2Left: [9]9index 0(none)(none) → return 9
3Right: [9,15,7,20]20 (root)index 3[15][7]
4Left: [15]15index 2(none)(none) → return 15
5Right: [7]7index 4(none)(none) → return 7

Result Tree:

3
/ \
9 20
/ \
15 7

Animated walkthrough

How HashMap reconstruction finds node positions

Use Next or Autoplay to watch how the postorder pointer, inorder position lookup, and left/right subtree splitting evolve.

Step 1 of 4 Target: HashMap
Waiting to begin...
Array state
Memory / lookup state

function buildTreeHashMap(inorder, postorder):
inorder_map = {}
for i, val in enumerate(inorder):
inorder_map[val] = i
function build(post_start, post_end, in_start, in_end):
if post_start > post_end or in_start > in_end:
return null
root_val = postorder[post_end]
root = TreeNode(root_val)
root_idx = inorder_map[root_val]
left_size = root_idx - in_start
root.left = build(post_start, post_start + left_size - 1, in_start, root_idx - 1)
root.right = build(post_start + left_size, post_end - 1, root_idx + 1, in_end)
return root
return build(0, len(postorder) - 1, 0, len(inorder) - 1)
construct_binary_tree_from_inorder_and_postorder_traversal_hash_map.py
from typing import Optional, List
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def buildTree(inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
"""
Construct binary tree from inorder and postorder traversal using HashMap.
Key insight:
- Postorder: left subtree, right subtree, root (last element is always root)
- Inorder: left subtree, root, right subtree
Use a HashMap to quickly find the root's position in inorder,
then recursively build left and right subtrees.
Time Complexity: O(n) where n is the number of nodes (HashMap lookup is O(1))
Space Complexity: O(n) for the HashMap and recursion call stack
"""
if not inorder or not postorder:
return None
# HashMap to store inorder values and their indices for O(1) lookup
inorder_map = {val: idx for idx, val in enumerate(inorder)}
def build(post_start: int, post_end: int, in_start: int, in_end: int) -> Optional[TreeNode]:
"""
Recursively build tree from postorder and inorder ranges.
Args:
post_start, post_end: Range in postorder array
in_start, in_end: Range in inorder array
"""
if post_start > post_end or in_start > in_end:
return None
# Last element in postorder range is the root
root_val = postorder[post_end]
root = TreeNode(root_val)
# Find root position in inorder
root_idx = inorder_map[root_val]
# Number of nodes in left subtree
left_size = root_idx - in_start
# Recursively build left subtree
# Postorder: [left subtree], [right subtree], root
# Inorder: [left subtree], root, [right subtree]
root.left = build(
post_start, # Left subtree starts at beginning of postorder
post_start + left_size - 1, # Left subtree ends after left_size elements
in_start, # Left subtree starts at beginning of inorder
root_idx - 1 # Left subtree ends before root
)
root.right = build(
post_start + left_size, # Right subtree starts after left subtree
post_end - 1, # Right subtree ends before root
root_idx + 1, # Right subtree starts after root
in_end # Right subtree ends at end of inorder
)
return root
return build(0, len(postorder) - 1, 0, len(inorder) - 1)
# Test cases
if __name__ == "__main__":
# Example 1: [3,9,20,null,null,15,7]
# 3
# / \
# 9 20
# / \
# 15 7
inorder1 = [9, 3, 15, 20, 7]
postorder1 = [9, 15, 7, 20, 3]
root1 = buildTree(inorder1, postorder1)
def inorder_traversal(node):
if not node:
return []
return inorder_traversal(node.left) + [node.val] + inorder_traversal(node.right)
def postorder_traversal(node):
if not node:
return []
return postorder_traversal(node.left) + postorder_traversal(node.right) + [node.val]
print(inorder_traversal(root1)) # Expected: [9, 3, 15, 20, 7]
print(postorder_traversal(root1)) # Expected: [9, 15, 7, 20, 3]
# Example 2: Single node
inorder2 = [1]
postorder2 = [1]
root2 = buildTree(inorder2, postorder2)
print(inorder_traversal(root2)) # Expected: [1]
# Example 3: Left skewed tree
inorder3 = [3, 2, 1]
postorder3 = [3, 2, 1]
root3 = buildTree(inorder3, postorder3)
print(inorder_traversal(root3)) # Expected: [3, 2, 1]
🎯 Interview Favourite

Instead of a HashMap, use an index pointer into the postorder array. Process the postorder sequence from right to left (backwards) and use indexOf() to find the root’s position in inorder each time.

The key insight is that traversing postorder backwards naturally aligns with the order in which we need to construct nodes (root first, then right, then left).

⏱ Time O(n²) Linear inorder search per node 💾 Space O(h) Recursion stack only

Input: inorder = [9, 3, 15, 20, 7], postorder = [9, 15, 7, 20, 3]

Processing postorder from right to left:

StepPostorder PointerValueInorder SearchAction
1index 43found at 1Create root, split subtrees
2index 320found at 3Create right subtree root
3index 27found at 4Create right child of 20
4index 115found at 2Create left child of 20
5index 09found at 0Create left child of root
function buildTreeIndexTracking(inorder, postorder):
post_idx = len(postorder) - 1
function build(in_start, in_end):
if in_start > in_end or post_idx < 0:
return null
root_val = postorder[post_idx]
post_idx--
root = TreeNode(root_val)
root_idx = inorder.indexOf(root_val)
root.right = build(root_idx + 1, in_end) // Right before left (postorder is reverse)
root.left = build(in_start, root_idx - 1)
return root
return build(0, len(inorder) - 1)
construct_binary_tree_from_inorder_and_postorder_traversal_index.py
from typing import Optional, List
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def buildTree(inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
"""
Construct binary tree from inorder and postorder traversal using index tracking.
Key insight:
- Postorder: left subtree, right subtree, root (last element is always root)
- Inorder: left subtree, root, right subtree
- Use a pointer to track the current root in postorder (traverse from end to start)
- Find root in inorder to split into left and right subtrees
Time Complexity: O(n²) in worst case due to linear search for root in inorder
O(n) if inorder is indexed (see hash_map approach)
Space Complexity: O(h) for recursion call stack where h is height
"""
if not inorder or not postorder:
return None
# Use a list to hold the postorder index as a reference (non-local variable)
post_idx = [len(postorder) - 1]
def build(in_start: int, in_end: int) -> Optional[TreeNode]:
"""
Recursively build tree by processing postorder from right to left.
Args:
in_start, in_end: Range in inorder array
"""
if in_start > in_end or post_idx[0] < 0:
return None
# Current postorder element (processing from end to start)
root_val = postorder[post_idx[0]]
post_idx[0] -= 1
root = TreeNode(root_val)
# Find root position in inorder
root_idx = inorder.index(root_val)
# Build right subtree first (postorder: left, right, root)
# Since we traverse postorder backwards, right comes before left
root.right = build(root_idx + 1, in_end)
# Build left subtree
root.left = build(in_start, root_idx - 1)
return root
return build(0, len(inorder) - 1)
# Test cases
if __name__ == "__main__":
# Example 1: [3,9,20,null,null,15,7]
# 3
# / \
# 9 20
# / \
# 15 7
inorder1 = [9, 3, 15, 20, 7]
postorder1 = [9, 15, 7, 20, 3]
root1 = buildTree(inorder1, postorder1)
def inorder_traversal(node):
if not node:
return []
return inorder_traversal(node.left) + [node.val] + inorder_traversal(node.right)
def postorder_traversal(node):
if not node:
return []
return postorder_traversal(node.left) + postorder_traversal(node.right) + [node.val]
print(inorder_traversal(root1)) # Expected: [9, 3, 15, 20, 7]
print(postorder_traversal(root1)) # Expected: [9, 15, 7, 20, 3]
# Example 2: Single node
inorder2 = [1]
postorder2 = [1]
root2 = buildTree(inorder2, postorder2)
print(inorder_traversal(root2)) # Expected: [1]
# Example 3: Left skewed tree
inorder3 = [3, 2, 1]
postorder3 = [3, 2, 1]
root3 = buildTree(inorder3, postorder3)
print(inorder_traversal(root3)) # Expected: [3, 2, 1]
✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
construct_binary_tree_from_inorder_and_postorder_traversal_space_optimized.py
"""
Solution for Construct Binary Tree from Inorder and Postorder Traversal
"""
def solve():
"""Implementation for approach 3 of Construct Binary Tree from Inorder and Postorder Traversal"""
pass
if __name__ == "__main__":
print("Solution ready")