# Definition for a binary tree node.
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, inorder, postorder):
if not inorder or not postorder:
return None
# Map value to index for quick lookup in inorder
idx_map = {val: idx for idx, val in enumerate(inorder)}
def helper(in_left, in_right):
if in_left > in_right:
return None
# Last element in postorder is root
root_val = postorder.pop()
root = TreeNode(root_val)
# Root splits inorder into left and right
index = idx_map[root_val]
# Build right subtree before left since we're popping from end
root.right = helper(index + 1, in_right)
root.left = helper(in_left, index - 1)
return root
return helper(0, len(inorder) - 1)
// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
public:
TreeNode* buildTree(vector& inorder, vector& postorder) {
unordered_map idx_map;
for (int i = 0; i < inorder.size(); ++i) {
idx_map[inorder[i]] = i;
}
int post_idx = postorder.size() - 1;
return helper(0, inorder.size() - 1, postorder, post_idx, idx_map);
}
private:
TreeNode* helper(int in_left, int in_right, vector& postorder, int& post_idx, unordered_map& idx_map) {
if (in_left > in_right) return nullptr;
int root_val = postorder[post_idx--];
TreeNode* root = new TreeNode(root_val);
int index = idx_map[root_val];
root->right = helper(index + 1, in_right, postorder, post_idx, idx_map);
root->left = helper(in_left, index - 1, postorder, post_idx, idx_map);
return root;
}
};
// Definition for a binary tree node.
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class Solution {
private Map<Integer, Integer> idxMap;
private int postIdx;
public TreeNode buildTree(int[] inorder, int[] postorder) {
idxMap = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
idxMap.put(inorder[i], i);
}
postIdx = postorder.length - 1;
return helper(0, inorder.length - 1, postorder);
}
private TreeNode helper(int inLeft, int inRight, int[] postorder) {
if (inLeft > inRight) return null;
int rootVal = postorder[postIdx--];
TreeNode root = new TreeNode(rootVal);
int index = idxMap.get(rootVal);
root.right = helper(index + 1, inRight, postorder);
root.left = helper(inLeft, index - 1, postorder);
return root;
}
}
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number[]} inorder
* @param {number[]} postorder
* @return {TreeNode}
*/
var buildTree = function(inorder, postorder) {
if (!inorder.length || !postorder.length) return null;
const idxMap = new Map();
inorder.forEach((val, idx) => idxMap.set(val, idx));
function helper(inLeft, inRight) {
if (inLeft > inRight) return null;
const rootVal = postorder.pop();
const root = new TreeNode(rootVal);
const index = idxMap.get(rootVal);
root.right = helper(index + 1, inRight);
root.left = helper(inLeft, index - 1);
return root;
}
return helper(0, inorder.length - 1);
};
Given two integer arrays inorder
and postorder
where inorder
is the inorder traversal of a binary tree and postorder
is the postorder traversal of the same tree, construct and return the binary tree.
You need to reconstruct the original binary tree structure from these two traversals.
When first approaching this problem, you might try to brute-force all possible trees and compare their traversals to the given arrays. However, this would be extremely inefficient, especially as the number of nodes increases.
Instead, we should leverage the properties of inorder and postorder traversals:
Left - Root - Right
): The root node divides the tree into left and right subtrees.Left - Right - Root
): The last element is always the root of the current tree/subtree.By recursively identifying the root from postorder and splitting the inorder array accordingly, we can efficiently reconstruct the tree.
We use recursion and a hash map for efficiency. Here are the steps:
inorder
to its index. This allows O(1) lookups for splitting.
postorder
(since the last element is the root).
postorder
as the current root.inorder
using the hash map.postorder
from the end).inorder
, return null (no subtree).
We use a hash map for quick index lookups and avoid slicing arrays by passing indices, which keeps the solution efficient.
Suppose inorder = [9,3,15,20,7]
and postorder = [9,15,7,20,3]
.
postorder
is 3
. This is the root.
inorder
, 3
is at index 1. So:
inorder[0:1] = [9]
inorder[2:5] = [15,20,7]
postorder
(remaining: [9,15,7,20]
):
20
(last element).inorder
, 20
is at index 3. So:[15]
[7]
20
is 7
, and left child is 15
. Both are leaf nodes.
3
using postorder
(remaining: [9]
):
9
, which is a leaf node.By understanding the properties of inorder and postorder traversals, we can reconstruct a unique binary tree efficiently. The key insight is to use the last element of postorder as the root, use a hash map for fast splits, and build the right subtree first due to the traversal order. This approach is both elegant and efficient, making optimal use of recursion and data structures.