Given two integer arrays Postorder and Inorder. Where Postorder is the preorder traversal of a binary tree and Inorder is the inorder traversal of the same tree.
Construct and return the binary using inorder and preorder arrays.
Input : postorder = [9, 15, 7, 20, 3] , inorder = [9, 3, 15, 20, 7]
Output : [3, 9, 20, null, null, 15, 7]
Explanation : The output tree is shown below.
Input : postorder = [5, 6, 4, 9, 2, 3] , inorder = [5, 4, 6, 3, 2, 9]
Output : [3, 4, 2, 5, 6, null, 9]
Explanation : The output tree is shown below.
Input : postorder = [6, 8, 1, 4, 7, 2, 5], inorder = [8, 6, 1, 5, 4, 2, 7]
The process of constructing a binary tree from inorder and postorder traversals involves understanding how these traversals reveal the tree's structure. The inorder traversal allows us to determine the left and right subtrees of each node, while the postorder traversal ensures that the root node is the last node visited. By utilizing these characteristics, the binary tree can be reconstructed uniquely. The fundamental approach employs a recursive algorithm that constructs the tree one node at a time. The root node is identified from the postorder traversal and located in the inorder traversal, which divides the array into left and right subtrees.
To optimize the process and avoid unnecessary duplication of arrays, variables (inStart, inEnd) and (postStart, postEnd) are used to define the boundaries of the current subtree within the inorder and postorder arrays, respectively. These variables delineate the sections of the arrays that pertain to the current subtree. By finding the root of a subtree within the inorder array, the left and right subtrees can be determined. Additionally, a hashmap is used to store the indices of elements in the inorder traversal, allowing for constant-time lookups and enhancing the efficiency of the reconstruction process.
buildTree
with the following parameters:
postStart
), initially set to 0postEnd
), initially set to postorder.size() - 1
inStart
), initially set to 0inEnd
), initially set to inorder.size() - 1
postStart
is greater than postEnd
or inStart
is greater than inEnd
. If true, return NULL, indicating an empty subtree/node.postorder[postEnd]
).inMap[rootValue]
). This is the rootIndex
.inStart
to rootIndex
. Subtracting these indexes gives the leftSubtreeSize
.buildTree
to build the left and right subtrees:
postStart
to postEnd - leftSubtreeSize
(moving to the next element in postorder)postEnd
to postEnd - 1
(end of left subtree in postorder)inEnd
to rootIndex - 1
(end of left subtree in inorder)postStart
to postStart
(moving to the next element in postorder)postEnd
to postEnd - leftSubtreeSize - 1
(end of right subtree in postorder)inStart
to rootIndex + 1
(start of right subtree in inorder)#include <bits/stdc++.h>
using namespace std;
// Definition for a binary tree node.
struct TreeNode {
int data;
TreeNode *left;
TreeNode *right;
TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.empty() || postorder.empty() || inorder.size() != postorder.size()) {
return nullptr;
}
// Create a map to store the indices of elements in the inorder traversal
unordered_map<int, int> inorderMap;
for (int i = 0; i < inorder.size(); ++i) {
inorderMap[inorder[i]] = i;
}
// Call the recursive function to build the binary tree
return buildTreeHelper(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1, inorderMap);
}
private:
TreeNode* buildTreeHelper(vector<int>& inorder, int inStart, int inEnd,
vector<int>& postorder, int postStart, int postEnd,
unordered_map<int, int>& inorderMap) {
if (inStart > inEnd || postStart > postEnd) {
return nullptr;
}
// Create the root node from the last element in postorder
int rootValue = postorder[postEnd];
TreeNode* root = new TreeNode(rootValue);
// Find the index of rootValue in inorder to determine the left and right subtrees
int rootIndexInorder = inorderMap[rootValue];
int leftSubtreeSize = rootIndexInorder - inStart;
// Recursive calls to build left and right subtrees
root->left = buildTreeHelper(inorder, inStart, rootIndexInorder - 1,
postorder, postStart, postStart + leftSubtreeSize - 1, inorderMap);
root->right = buildTreeHelper(inorder, rootIndexInorder + 1, inEnd,
postorder, postStart + leftSubtreeSize, postEnd - 1, inorderMap);
return root;
}
};
// Function to print the inorder traversal of a tree
void printInorder(TreeNode* root) {
if (!root) {
return;
}
printInorder(root->left);
cout << root->data << " ";
printInorder(root->right);
}
// Function to print the given vector
void printVector(vector<int>& vec) {
for (int num : vec) {
cout << num << " ";
}
cout << endl;
}
int main() {
// Example input vectors
vector<int> inorder = {40, 20, 50, 10, 60, 30};
vector<int> postorder = {40, 50, 20, 60, 30, 10};
// Display the input vectors
cout << "Inorder Vector: ";
printVector(inorder);
cout << "Postorder Vector: ";
printVector(postorder);
Solution sol;
// Build the binary tree and print its inorder traversal
TreeNode* root = sol.buildTree(inorder, postorder);
cout << "Inorder of Unique Binary Tree Created: " << endl;
printInorder(root);
cout << endl;
return 0;
}
import java.util.*;
class TreeNode {
int data;
TreeNode left;
TreeNode right;
TreeNode(int val) {
data = val;
left = null;
right = null;
}
}
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder.length != postorder.length) {
return null;
}
// Create a map to store the indices
// of elements in the inorder traversal
Map<Integer, Integer> hm = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
hm.put(inorder[i], i);
}
// Call the recursive function
// to build the binary tree
return buildTreePostIn(inorder, 0, inorder.length - 1, postorder, 0,
postorder.length - 1, hm);
}
// Recursive function to build a binary
// tree from inorder and postorder traversals
public TreeNode buildTreePostIn(int[] inorder, int is, int ie,
int[] postorder, int ps, int pe, Map<Integer, Integer> hm) {
// Base case: If the subtree
// is empty, return null
if (ps > pe || is > ie) {
return null;
}
// Create a new TreeNode
// with the root value from postorder
TreeNode root = new TreeNode(postorder[pe]);
// Find the index of the root
// value in inorder traversal
int inRoot = hm.get(postorder[pe]);
// Number of nodes in the left subtree
int numsLeft = inRoot - is;
// Recursively build the
// left and right subtrees
root.left = buildTreePostIn(inorder, is, inRoot - 1, postorder,
ps, ps + numsLeft - 1, hm);
root.right = buildTreePostIn(inorder, inRoot + 1, ie, postorder,
ps + numsLeft, pe - 1, hm);
// Return the root of
// the constructed subtree
return root;
}
}
public class Main {
// Function to print the
// inorder traversal of a tree
public static void printInorder(TreeNode root) {
if (root == null) {
return;
}
printInorder(root.left);
System.out.print(root.data + " ");
printInorder(root.right);
}
// Function to print the given array
public static void printArray(int[] arr) {
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
}
public static void main(String[] args) {
// Example input arrays
int[] inorder = {40, 20, 50, 10, 60, 30};
int[] postorder = {40, 50, 20, 60, 30, 10};
// Display the input arrays
System.out.print("Inorder Array: ");
printArray(inorder);
System.out.print("Postorder Array: ");
printArray(postorder);
Solution sol = new Solution();
// Build the binary tree and
// print its inorder traversal
TreeNode root = sol.buildTree(inorder, postorder);
System.out.println("Inorder of Unique Binary Tree Created: ");
printInorder(root);
System.out.println();
}
}
from typing import List
from collections import deque
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.data = val
self.left = left
self.right = right
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
if len(inorder) != len(postorder):
return None
# Create a map to store the indices
# of elements in the inorder traversal
hm = {}
for i, val in enumerate(inorder):
hm[val] = i
# Call the recursive function
# to build the binary tree
return self.buildTreePostIn(inorder, 0, len(inorder) - 1, postorder, 0,
len(postorder) - 1, hm)
# Recursive function to build a binary
# tree from inorder and postorder traversals
def buildTreePostIn(self, inorder: List[int], is_: int, ie: int,
postorder: List[int], ps: int, pe: int,
hm: dict) -> TreeNode:
# Base case: If the subtree
# is empty, return None
if ps > pe or is_ > ie:
return None
# Create a new TreeNode
# with the root value from postorder
root = TreeNode(postorder[pe])
# Find the index of the root
# value in inorder traversal
inRoot = hm[postorder[pe]]
# Number of nodes in the left subtree
numsLeft = inRoot - is_
# Recursively build the
# left and right subtrees
root.left = self.buildTreePostIn(inorder, is_, inRoot - 1, postorder,
ps, ps + numsLeft - 1, hm)
root.right = self.buildTreePostIn(inorder, inRoot + 1, ie, postorder,
ps + numsLeft, pe - 1, hm)
# Return the root of
# the constructed subtree
return root
def printInorder(root: TreeNode):
if not root:
return
printInorder(root.left)
print(root.data, end=" ")
printInorder(root.right)
def printList(lst: List[int]):
for num in lst:
print(num, end=" ")
print()
if __name__ == "__main__":
# Example input lists
inorder = [40, 20, 50, 10, 60, 30]
postorder = [40, 50, 20, 60, 30, 10]
# Display the input lists
print("Inorder List:", end=" ")
printList(inorder)
print("Postorder List:", end=" ")
printList(postorder)
sol = Solution()
# Build the binary tree and
# print its inorder traversal
root = sol.buildTree(inorder, postorder)
print("Inorder of Unique Binary Tree Created:")
printInorder(root)
print()
/**
* Definition for a binary tree node.
*/
class TreeNode {
constructor(val = 0, left = null, right = null) {
this.data = val;
this.left = left;
this.right = right;
}
}
class Solution {
buildTree(inorder, postorder) {
if (inorder.length !== postorder.length) {
return null;
}
// Create a map to store the indices
// of elements in the inorder traversal
let hm = new Map();
for (let i = 0; i < inorder.length; i++) {
hm.set(inorder[i], i);
}
// Call the recursive function
// to build the binary tree
return this.buildTreePostIn(inorder, 0, inorder.length - 1, postorder, 0,
postorder.length - 1, hm);
}
// Recursive function to build a binary
// tree from inorder and postorder traversals
buildTreePostIn(inorder, is, ie, postorder, ps, pe, hm) {
// Base case: If the subtree
// is empty, return null
if (ps > pe || is > ie) {
return null;
}
// Create a new TreeNode
// with the root value from postorder
let root = new TreeNode(postorder[pe]);
// Find the index of the root
// value in inorder traversal
let inRoot = hm.get(postorder[pe]);
// Number of nodes in the left subtree
let numsLeft = inRoot - is;
// Recursively build the
// left and right subtrees
root.left = this.buildTreePostIn(inorder, is, inRoot - 1, postorder,
ps, ps + numsLeft - 1, hm);
root.right = this.buildTreePostIn(inorder, inRoot + 1, ie, postorder,
ps + numsLeft, pe - 1, hm);
// Return the root of
// the constructed subtree
return root;
}
}
// Function to print the
// inorder traversal of a tree
function printInorder(root) {
if (!root) {
return;
}
printInorder(root.left);
process.stdout.write(root.data + " ");
printInorder(root.right);
}
// Function to print the given array
function printArray(arr) {
for (let num of arr) {
process.stdout.write(num + " ");
}
console.log();
}
// Example input arrays
let inorder = [40, 20, 50, 10, 60, 30];
let postorder = [40, 50, 20, 60, 30, 10];
// Display the input arrays
console.log("Inorder Array:", end=" ");
printArray(inorder);
console.log("Postorder Array:", end=" ");
printArray(postorder);
let sol = new Solution();
// Build the binary tree and
// print its inorder traversal
let root = sol.buildTree(inorder, postorder);
console.log("Inorder of Unique Binary Tree Created:");
printInorder(root);
console.log();
Q: What happens if duplicates exist in the arrays?
A: The approach fails because locating the root in inorder is not unique. To handle duplicates, we can use additional information like index maps.
Q: How do we optimize repeated root lookups in inorder?
A: Use a HashMap (dictionary) to store inorder value → index mappings, reducing lookup time to O(1).
Q: How does this problem relate to real-world applications?
A: Rebuilding expression trees from syntax orders, deserialization of tree structures.