Build Binary Tree from Preorder and Inorder Traversal
Preorder gives the next root; index lookup in inorder splits left and right subtree ranges.
4 min read
tree dfs divide-and-conquer
Problem#
Given preorder and inorder traversal arrays of a binary tree with unique values, reconstruct and return the tree.
Examples#
preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]→ tree with root 3.preorder = [-1], inorder = [-1]→ single node.
Constraints#
1 <= preorder.length <= 3000. All values are unique.
Approach#
Preorder’s first element is the root. Find its index in inorder — everything left is the left subtree’s inorder, everything right is the right subtree’s inorder. Slice preorder accordingly. Use a hash map for O(1) inorder lookup.
Solution#
class Solution {public: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { unordered_map<int,int> idx; for (int i = 0; i < (int)inorder.size(); ++i) idx[inorder[i]] = i; int p = 0; function<TreeNode*(int,int)> build = [&](int lo, int hi) -> TreeNode* { if (lo > hi) return nullptr; int v = preorder[p++]; TreeNode* node = new TreeNode(v); int m = idx[v]; node->left = build(lo, m - 1); node->right = build(m + 1, hi); return node; }; return build(0, inorder.size() - 1); }};func buildTree(preorder []int, inorder []int) *TreeNode { idx := make(map[int]int, len(inorder)) for i, v := range inorder { idx[v] = i } p := 0 var build func(lo, hi int) *TreeNode build = func(lo, hi int) *TreeNode { if lo > hi { return nil } v := preorder[p] p++ node := &TreeNode{Val: v} m := idx[v] node.Left = build(lo, m-1) node.Right = build(m+1, hi) return node } return build(0, len(inorder)-1)}from typing import List, Optional
# class TreeNode:# def __init__(self, val=0, left=None, right=None):# self.val = val# self.left = left# self.right = right
class Solution: def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: idx = {v: i for i, v in enumerate(inorder)} self.p = 0 def build(lo: int, hi: int) -> Optional[TreeNode]: if lo > hi: return None v = preorder[self.p] self.p += 1 node = TreeNode(v) m = idx[v] node.left = build(lo, m - 1) node.right = build(m + 1, hi) return node return build(0, len(inorder) - 1)function buildTree(preorder, inorder) { const idx = new Map(); for (let i = 0; i < inorder.length; i++) idx.set(inorder[i], i); let p = 0; const build = (lo, hi) => { if (lo > hi) return null; const v = preorder[p++]; const node = new TreeNode(v); const m = idx.get(v); node.left = build(lo, m - 1); node.right = build(m + 1, hi); return node; }; return build(0, inorder.length - 1);}class Solution { private int[] preorder; private Map<Integer, Integer> idx = new HashMap<>(); private int p = 0;
public TreeNode buildTree(int[] preorder, int[] inorder) { this.preorder = preorder; for (int i = 0; i < inorder.length; i++) idx.put(inorder[i], i); return build(0, inorder.length - 1); }
private TreeNode build(int lo, int hi) { if (lo > hi) return null; int v = preorder[p++]; TreeNode node = new TreeNode(v); int m = idx.get(v); node.left = build(lo, m - 1); node.right = build(m + 1, hi); return node; }}function buildTree(preorder: number[], inorder: number[]): TreeNode | null { const idx = new Map<number, number>(); for (let i = 0; i < inorder.length; i++) idx.set(inorder[i], i); let p = 0; const build = (lo: number, hi: number): TreeNode | null => { if (lo > hi) return null; const v = preorder[p++]; const node = new TreeNode(v); const m = idx.get(v)!; node.left = build(lo, m - 1); node.right = build(m + 1, hi); return node; }; return build(0, inorder.length - 1);}Editorial#
The preorder cursor p advances exactly n times, and each call does O(1) hash lookup. Building left first matches the preorder consumption order — switching to “right first” would corrupt the cursor.
Complexity#
- Time: O(n).
- Space: O(n).
Concept revision#
Related#