🧠
Optimized Recursion with Hash Map for Index Lookup
💡 This approach improves the brute force by avoiding repeated linear searches for root index in inorder, using a hash map for O(1) lookups. It also avoids slicing arrays by passing indices, which saves memory and time.
Intuition
Store each value's index in inorder in a hash map. Use indices to avoid slicing arrays, passing start and end indices instead. This reduces time complexity significantly.
Algorithm
- Build a hash map of value to index from inorder array.
- Use a recursive helper with parameters for current inorder and postorder subarray indices.
- Root is postorder[end_post], find root index in inorder using hash map.
- Recursively build left and right subtrees using updated indices without slicing arrays.
💡 Passing indices instead of slicing arrays avoids extra memory and speeds up recursion.
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(inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
idx_map = {val: idx for idx, val in enumerate(inorder)}
def helper(in_left, in_right, post_left, post_right):
if in_left > in_right or post_left > post_right:
return None
root_val = postorder[post_right]
root = TreeNode(root_val)
root_index = idx_map[root_val]
left_size = root_index - in_left
root.left = helper(in_left, root_index - 1, post_left, post_left + left_size - 1)
root.right = helper(root_index + 1, in_right, post_left + left_size, post_right - 1)
return root
return helper(0, len(inorder) - 1, 0, len(postorder) - 1)
# Example usage:
# inorder = [9,3,15,20,7]
# postorder = [9,15,7,20,3]
# root = buildTree(inorder, postorder)
Line Notes
idx_map = {val: idx for idx, val in enumerate(inorder)}Precompute indices for O(1) root lookup
def helper(in_left, in_right, post_left, post_right):Helper uses indices to avoid slicing
if in_left > in_right or post_left > post_right:Base case: no nodes in this subtree
root_val = postorder[post_right]Root is last element in current postorder segment
root_index = idx_map[root_val]Find root index in inorder using hash map
left_size = root_index - in_leftCalculate size of left subtree to split postorder
root.left = helper(in_left, root_index - 1, post_left, post_left + left_size - 1)Build left subtree recursively
root.right = helper(root_index + 1, in_right, post_left + left_size, post_right - 1)Build right subtree recursively
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class Solution {
private Map<Integer, Integer> idxMap;
private int[] postorder;
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.postorder = postorder;
idxMap = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
idxMap.put(inorder[i], i);
}
return helper(0, inorder.length - 1, 0, postorder.length - 1);
}
private TreeNode helper(int inLeft, int inRight, int postLeft, int postRight) {
if (inLeft > inRight || postLeft > postRight) return null;
int rootVal = postorder[postRight];
TreeNode root = new TreeNode(rootVal);
int rootIndex = idxMap.get(rootVal);
int leftSize = rootIndex - inLeft;
root.left = helper(inLeft, rootIndex - 1, postLeft, postLeft + leftSize - 1);
root.right = helper(rootIndex + 1, inRight, postLeft + leftSize, postRight - 1);
return root;
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] inorder = {9,3,15,20,7};
int[] postorder = {9,15,7,20,3};
TreeNode root = sol.buildTree(inorder, postorder);
System.out.println(root.val); // 3
}
}
Line Notes
idxMap = new HashMap<>();Hash map stores inorder indices for O(1) lookup
for (int i = 0; i < inorder.length; i++)Populate hash map with value to index
if (inLeft > inRight || postLeft > postRight) return null;Base case: no nodes in current subtree
int rootVal = postorder[postRight];Root is last element in current postorder segment
int rootIndex = idxMap.get(rootVal);Get root index from hash map
int leftSize = rootIndex - inLeft;Calculate left subtree size to split postorder
root.left = helper(inLeft, rootIndex - 1, postLeft, postLeft + leftSize - 1);Build left subtree recursively
root.right = helper(rootIndex + 1, inRight, postLeft + leftSize, postRight - 1);Build right subtree recursively
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
unordered_map<int, int> idxMap;
vector<int> postorder;
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
this->postorder = postorder;
for (int i = 0; i < inorder.size(); i++) {
idxMap[inorder[i]] = i;
}
return helper(0, inorder.size() - 1, 0, postorder.size() - 1);
}
private:
TreeNode* helper(int inLeft, int inRight, int postLeft, int postRight) {
if (inLeft > inRight || postLeft > postRight) return nullptr;
int rootVal = postorder[postRight];
TreeNode* root = new TreeNode(rootVal);
int rootIndex = idxMap[rootVal];
int leftSize = rootIndex - inLeft;
root->left = helper(inLeft, rootIndex - 1, postLeft, postLeft + leftSize - 1);
root->right = helper(rootIndex + 1, inRight, postLeft + leftSize, postRight - 1);
return root;
}
};
int main() {
vector<int> inorder = {9,3,15,20,7};
vector<int> postorder = {9,15,7,20,3};
Solution sol;
TreeNode* root = sol.buildTree(inorder, postorder);
cout << root->val << endl; // 3
return 0;
}
Line Notes
unordered_map<int, int> idxMap;Hash map for O(1) index lookup in inorder
for (int i = 0; i < inorder.size(); i++)Fill hash map with value to index
if (inLeft > inRight || postLeft > postRight) return nullptr;Base case: no nodes to build
int rootVal = postorder[postRight];Root is last element in current postorder segment
int rootIndex = idxMap[rootVal];Get root index from hash map
int leftSize = rootIndex - inLeft;Calculate left subtree size
root->left = helper(inLeft, rootIndex - 1, postLeft, postLeft + leftSize - 1);Build left subtree recursively
root->right = helper(rootIndex + 1, inRight, postLeft + leftSize, postRight - 1);Build right subtree recursively
function TreeNode(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
function buildTree(inorder, postorder) {
const idxMap = new Map();
inorder.forEach((val, idx) => idxMap.set(val, idx));
function helper(inLeft, inRight, postLeft, postRight) {
if (inLeft > inRight || postLeft > postRight) return null;
const rootVal = postorder[postRight];
const root = new TreeNode(rootVal);
const rootIndex = idxMap.get(rootVal);
const leftSize = rootIndex - inLeft;
root.left = helper(inLeft, rootIndex - 1, postLeft, postLeft + leftSize - 1);
root.right = helper(rootIndex + 1, inRight, postLeft + leftSize, postRight - 1);
return root;
}
return helper(0, inorder.length - 1, 0, postorder.length - 1);
}
// Example usage:
// const inorder = [9,3,15,20,7];
// const postorder = [9,15,7,20,3];
// const root = buildTree(inorder, postorder);
// console.log(root.val); // 3
Line Notes
const idxMap = new Map();Map for O(1) index lookup in inorder
inorder.forEach((val, idx) => idxMap.set(val, idx));Populate map with value to index
if (inLeft > inRight || postLeft > postRight) return null;Base case: no nodes in subtree
const rootVal = postorder[postRight];Root is last element in current postorder segment
const rootIndex = idxMap.get(rootVal);Get root index from map
const leftSize = rootIndex - inLeft;Calculate left subtree size
root.left = helper(inLeft, rootIndex - 1, postLeft, postLeft + leftSize - 1);Build left subtree recursively
root.right = helper(rootIndex + 1, inRight, postLeft + leftSize, postRight - 1);Build right subtree recursively
Each node is processed once. Hash map lookup is O(1). No array slicing reduces overhead.
💡 For n=20, about 20 operations, which is efficient and scalable.
Interview Verdict: Accepted and efficient
This is the standard approach to code in interviews for this problem.