Practice Problem Link: Construct Binary Tree from Inorder and Postorder Traversal
Please make sure to try solving the problem yourself before looking at the editorial.
Problem Statement
Given the postorder and inorder traversals of a binary tree, construct and return the binary tree.
Naive Approach
The problem can be solved recursively based on the fact that in postorder traversal the root is visited after its children.
- Pick an element from the end of the postorder traversal and create a new node using that element say
currNode. - Search the index of that element in the inorder traversal. Let the index be
currInorderIndex. - All the elements before the
currInorderIndexmust be part of the left subtree of thecurrNodeand all the elements after it must be part of the right subtree of thecurrNode. - Recursively repeat the above steps for the elements after the
currInorderIndexand make them the right subtree of thecurrNode. - Recursively repeat the above steps for the elements before the
currInorderIndexand make them the left subtree of thecurrNode. - Return
currNode.
Analysis
- Time Complexity:
O(n2) - Auxiliary Space Complexity:
O(1)
Implementation
C++
/* This is the Node class definition
class Node {
public:
Node* left;
Node* right;
int data;
Node(int data) {
this->left = NULL;
this->right = NULL;
this->data = data;
}
};
*/
Node* constructTreeUtil(vector<int> &postorder, int &postorderIndex, vector<int> &inorder, int inorderStart, int inorderEnd) {
if (inorderStart > inorderEnd) {
return NULL;
}
Node* currNode = new Node(postorder[postorderIndex]);
postorderIndex--;
if (inorderStart == inorderEnd) {
return currNode;
}
int currInorderIndex = - 1;
for (int i = inorderStart; i <= inorderEnd; i++) {
if(inorder[i] == currNode->data) {
currInorderIndex = i;
break;
}
}
currNode->right = constructTreeUtil(postorder, postorderIndex, inorder, currInorderIndex + 1, inorderEnd);
currNode->left = constructTreeUtil(postorder, postorderIndex, inorder, inorderStart, currInorderIndex - 1);
return currNode;
}
Node* constructTree(vector<int> &postorder, vector<int> &inorder) {
int postorderIndex = postorder.size() - 1;
return constructTreeUtil(postorder, postorderIndex, inorder, 0, inorder.size() - 1);
}Java
/* This is the Node class definition
class Node {
public Node left;
public Node right;
int data;
Node(int data) {
this.data = data;
}
}
*/
class Solution {
static int postorderIndex;
Node constructTreeUtil(int[] postorder, int[] inorder, int inorderStart, int inorderEnd) {
if (inorderStart > inorderEnd) {
return null;
}
Node currNode = new Node(postorder[postorderIndex]);
postorderIndex--;
if (inorderStart == inorderEnd) {
return currNode;
}
int currInorderIndex = - 1;
for (int i = inorderStart; i <= inorderEnd; i++) {
if(inorder[i] == currNode.data) {
currInorderIndex = i;
break;
}
}
currNode.right = constructTreeUtil(postorder, inorder, currInorderIndex + 1, inorderEnd);
currNode.left = constructTreeUtil(postorder, inorder, inorderStart, currInorderIndex - 1);
return currNode;
}
Node constructTree(int[] postorder, int[] inorder) {
postorderIndex = postorder.length - 1;
return constructTreeUtil(postorder, inorder, 0, inorder.length - 1);
}
}Optimal Approach
The naive approach can be optimized by storing the indexes of inorder traversal in a hashmap. By doing this, searching can be done in O(1) time.
Analysis
- Time Complexity:
O(n) - Auxiliary Space Complexity:
O(n)
Implementation
C++
/* This is the Node class definition
class Node {
public:
Node* left;
Node* right;
int data;
Node(int data) {
this->left = NULL;
this->right = NULL;
this->data = data;
}
};
*/
unordered_map<int, int> inorderIndex;
Node* constructTreeUtil(vector<int> &postorder, int &postorderIndex, vector<int> &inorder, int inorderStart, int inorderEnd) {
if (inorderStart > inorderEnd) {
return NULL;
}
Node* currNode = new Node(postorder[postorderIndex]);
postorderIndex--;
if (inorderStart == inorderEnd) {
return currNode;
}
int currInorderIndex = inorderIndex[currNode->data];
currNode->right = constructTreeUtil(postorder, postorderIndex, inorder, currInorderIndex + 1, inorderEnd);
currNode->left = constructTreeUtil(postorder, postorderIndex, inorder, inorderStart, currInorderIndex - 1);
return currNode;
}
Node* constructTree(vector<int> &postorder, vector<int> &inorder) {
inorderIndex.clear();
for (int i = 0; i < inorder.size(); i++) {
inorderIndex[inorder[i]] = i;
}
int postorderIndex = postorder.size() - 1;
return constructTreeUtil(postorder, postorderIndex, inorder, 0, inorder.size() - 1);
}Java
/* This is the Node class definition
class Node {
public Node left;
public Node right;
int data;
Node(int data) {
this.data = data;
}
}
*/
class Solution {
HashMap<Integer, Integer> inorderIndex = new HashMap<Integer, Integer>();
static int postorderIndex;
Node constructTreeUtil(int[] postorder, int[] inorder, int inorderStart, int inorderEnd) {
if (inorderStart > inorderEnd) {
return null;
}
Node currNode = new Node(postorder[postorderIndex]);
postorderIndex--;
if (inorderStart == inorderEnd) {
return currNode;
}
int currInorderIndex = inorderIndex.get(currNode.data);
currNode.right = constructTreeUtil(postorder, inorder, currInorderIndex + 1, inorderEnd);
currNode.left = constructTreeUtil(postorder, inorder, inorderStart, currInorderIndex - 1);
return currNode;
}
Node constructTree(int[] postorder, int[] inorder) {
inorderIndex.clear();
for (int i = 0; i < inorder.length; i++) {
inorderIndex.put(inorder[i], i);
}
postorderIndex = postorder.length - 1;
return constructTreeUtil(postorder, inorder, 0, inorder.length - 1);
}
}