🧠
Optimized Recursion with Hash Map for Inorder Indices
💡 This approach improves efficiency by avoiding repeated searches for root indices in inorder using a hash map, reducing time complexity to O(n).
Intuition
Store inorder value to index mappings in a hash map to find root positions in O(1). Use indices instead of slicing arrays to avoid extra space and time overhead.
Algorithm
- Build a hash map from inorder values to their indices.
- Define a recursive helper with preorder index and inorder start/end indices.
- Use preorder index to get root value, find root index in inorder via hash map.
- Recursively build left subtree with inorder start to root index - 1.
- Recursively build right subtree with root index + 1 to inorder end.
- Return the constructed root node.
💡 Passing indices instead of slicing arrays avoids overhead and hash map lookup makes root finding efficient.
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
def buildTree(preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
inorder_index_map = {val: idx for idx, val in enumerate(inorder)}
preorder_index = 0
def helper(in_left, in_right):
nonlocal preorder_index
if in_left > in_right:
return None
root_val = preorder[preorder_index]
root = TreeNode(root_val)
preorder_index += 1
root_index = inorder_index_map[root_val]
root.left = helper(in_left, root_index - 1)
root.right = helper(root_index + 1, in_right)
return root
return helper(0, len(inorder) - 1)
# Driver code
if __name__ == '__main__':
pre = [3,9,20,15,7]
ino = [9,3,15,20,7]
root = buildTree(pre, ino)
print(root.val) # Should print 3
Line Notes
inorder_index_map = {val: idx for idx, val in enumerate(inorder)}Precompute inorder indices for O(1) root lookup
preorder_index = 0Global pointer to track current root in preorder
def helper(in_left, in_right):Recursive helper to build subtree within inorder boundaries
if in_left > in_right:Base case: no nodes in this subtree
root_val = preorder[preorder_index]Get current root from preorder
root = TreeNode(root_val)Create root node
preorder_index += 1Move to next root for subsequent calls
root_index = inorder_index_map[root_val]Find root position in inorder quickly
root.left = helper(in_left, root_index - 1)Recursively build left subtree
root.right = helper(root_index + 1, in_right)Recursively build right subtree
return rootReturn constructed root node
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
private int preorderIndex = 0;
private Map<Integer, Integer> inorderIndexMap = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
for (int i = 0; i < inorder.length; i++) {
inorderIndexMap.put(inorder[i], i);
}
return helper(preorder, 0, inorder.length - 1);
}
private TreeNode helper(int[] preorder, int inLeft, int inRight) {
if (inLeft > inRight) return null;
int rootVal = preorder[preorderIndex++];
TreeNode root = new TreeNode(rootVal);
int rootIndex = inorderIndexMap.get(rootVal);
root.left = helper(preorder, inLeft, rootIndex - 1);
root.right = helper(preorder, rootIndex + 1, inRight);
return root;
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] pre = {3,9,20,15,7};
int[] ino = {9,3,15,20,7};
TreeNode root = sol.buildTree(pre, ino);
System.out.println(root.val); // Should print 3
}
}
Line Notes
private int preorderIndex = 0;Track current root index in preorder
private Map<Integer, Integer> inorderIndexMap = new HashMap<>();Map for O(1) inorder index lookup
for (int i = 0; i < inorder.length; i++)Build map from inorder values to indices
if (inLeft > inRight) return null;Base case: no subtree nodes
int rootVal = preorder[preorderIndex++];Get root and increment preorder index
TreeNode root = new TreeNode(rootVal);Create root node
int rootIndex = inorderIndexMap.get(rootVal);Find root position in inorder quickly
root.left = helper(preorder, inLeft, rootIndex - 1);Recursively build left subtree
root.right = helper(preorder, rootIndex + 1, inRight);Recursively build right subtree
return root;Return constructed root node
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
unordered_map<int, int> inorderIndexMap;
int preorderIndex = 0;
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
for (int i = 0; i < inorder.size(); i++) {
inorderIndexMap[inorder[i]] = i;
}
return helper(preorder, 0, inorder.size() - 1);
}
TreeNode* helper(vector<int>& preorder, int inLeft, int inRight) {
if (inLeft > inRight) return nullptr;
int rootVal = preorder[preorderIndex++];
TreeNode* root = new TreeNode(rootVal);
int rootIndex = inorderIndexMap[rootVal];
root->left = helper(preorder, inLeft, rootIndex - 1);
root->right = helper(preorder, rootIndex + 1, inRight);
return root;
}
};
int main() {
Solution sol;
vector<int> pre = {3,9,20,15,7};
vector<int> ino = {9,3,15,20,7};
TreeNode* root = sol.buildTree(pre, ino);
cout << root->val << endl; // Should print 3
return 0;
}
Line Notes
unordered_map<int, int> inorderIndexMap;Hash map for quick inorder index lookup
int preorderIndex = 0;Global preorder index pointer
for (int i = 0; i < inorder.size(); i++)Build map from inorder values to indices
if (inLeft > inRight) return nullptr;Base case: no nodes in subtree
int rootVal = preorder[preorderIndex++];Get root and advance preorder index
TreeNode* root = new TreeNode(rootVal);Create root node
int rootIndex = inorderIndexMap[rootVal];Find root index in inorder efficiently
root->left = helper(preorder, inLeft, rootIndex - 1);Recursively build left subtree
root->right = helper(preorder, rootIndex + 1, inRight);Recursively build right subtree
return root;Return constructed root node
function TreeNode(val, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
function buildTree(preorder, inorder) {
const inorderIndexMap = new Map();
for (let i = 0; i < inorder.length; i++) {
inorderIndexMap.set(inorder[i], i);
}
let preorderIndex = 0;
function helper(inLeft, inRight) {
if (inLeft > inRight) return null;
const rootVal = preorder[preorderIndex++];
const root = new TreeNode(rootVal);
const rootIndex = inorderIndexMap.get(rootVal);
root.left = helper(inLeft, rootIndex - 1);
root.right = helper(rootIndex + 1, inRight);
return root;
}
return helper(0, inorder.length - 1);
}
// Test
const pre = [3,9,20,15,7];
const ino = [9,3,15,20,7];
const root = buildTree(pre, ino);
console.log(root.val); // Should print 3
Line Notes
const inorderIndexMap = new Map();Create map for O(1) inorder index lookup
for (let i = 0; i < inorder.length; i++)Build map from inorder values to indices
let preorderIndex = 0;Track current root index in preorder
if (inLeft > inRight) return null;Base case: no subtree nodes
const rootVal = preorder[preorderIndex++];Get root and increment preorder index
const root = new TreeNode(rootVal);Create root node
const rootIndex = inorderIndexMap.get(rootVal);Find root position in inorder quickly
root.left = helper(inLeft, rootIndex - 1);Recursively build left subtree
root.right = helper(rootIndex + 1, inRight);Recursively build right subtree
return root;Return constructed root node
Each node is processed once, and root lookup is O(1) via hash map. Space is O(n) for recursion stack and hash map.
💡 For n=20, this means about 20 operations, making it efficient for large inputs.
Interview Verdict: Accepted
This is the standard efficient approach for this problem and is expected in interviews.