
Problem Statement
In the given challenge, we are provided with two integer arrays named inorder
and postorder
. These arrays represent the inorder and postorder traversal sequences of a binary tree, respectively. The task is to reconstruct the original binary tree from these traversal sequences. The reconstructed binary tree should mirror the structure and values present in the initial tree based on the provided traversals.
Examples
Example 1
Input:
inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
Output:
[3,9,20,null,null,15,7]
Example 2
Input:
inorder = [-1], postorder = [-1]
Output:
[-1]
Constraints
1 <= inorder.length <= 3000
postorder.length == inorder.length
-3000 <= inorder[i], postorder[i] <= 3000
inorder
andpostorder
consist of unique values.- Each value of
postorder
also appears ininorder
. inorder
is guaranteed to be the inorder traversal of the tree.postorder
is guaranteed to be the postorder traversal of the tree.
Approach and Intuition
Recursive Method to Construct the Binary Tree
The key understanding here is that the last element in the
postorder
array represents the root of the tree. This is a defining feature of postorder traversal where a node is processed after its subtrees.Knowing the root, the
inorder
array can be split into two parts:- All elements to the left of the root in the
inorder
array will belong to the left subtree. - All elements to the right of the root in the
inorder
array will belong to the right subtree.
- All elements to the left of the root in the
Using the identified root from the
postorder
array, you can divide theinorder
array into two halves at the root's position. This positional information then guides the split in the postorder array as well.This process is recursive:
- The next root will be the previous root's right neighbor in the
postorder
array for the right subtree. - Similarly, it will be the immediate previous element for the left subtree before the original root.
- The next root will be the previous root's right neighbor in the
Continue this recursive division until:
- All elements are processed.
- The subarrays for
inorder
orpostorder
become empty which indicates that you've reached a leaf node.
Edge cases:
- When the
inorder
andpostorder
arrays contain only one element. This scenario means the tree consists of a single node or a leaf node in recursive calls.
- When the
Example Walkthrough
The perspective approach can be illustrated using the provided examples:
For Example 1
- Input:
inorder = [9,3,15,20,7]
,postorder = [9,15,7,20,3]
- The root can be identified to be
3
from the postorder last element. - Now, split at
3
ininorder
, constructing subtrees with[9]
for left, and[15,20,7]
for right. - This process will continue recursively based on the new roots identified from the postorder array.
For Example 2
- Input:
inorder = [-1]
,postorder = [-1]
- Since there is only one element, it's straightforward. The tree will consist of a single node with value
-1
.
This recursive approach ensures that each element is used to correctly partition and construct subtrees accurately maintaining all binary tree properties according to the traversals provided.
Solutions
- C++
- Java
- C
- JavaScript
- Python
class Solution {
int current_post_idx;
vector<int> postorder_seq;
vector<int> inorder_seq;
unordered_map<int, int> val_to_index_map;
public:
TreeNode* construct_subtree(int in_left, int in_right) {
if (in_left > in_right) return NULL;
int root_value = postorder_seq[current_post_idx];
TreeNode* root_node = new TreeNode(root_value);
int split_index = val_to_index_map[root_value];
current_post_idx--;
root_node->right = construct_subtree(split_index + 1, in_right);
root_node->left = construct_subtree(in_left, split_index - 1);
return root_node;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
this->postorder_seq = postorder;
this->inorder_seq = inorder;
current_post_idx = postorder.size() - 1;
int index_counter = 0;
for (int value : inorder) val_to_index_map[value] = index_counter++;
return construct_subtree(0, inorder.size() - 1);
}
};
In the provided C++ solution, the goal is to reconstruct a binary tree from given inorder and postorder traversal sequences. Here’s a breakdown of how this solution efficiently accomplishes the task:
Data Structures Used:
- An integer (
current_post_idx
) to track the current index in the postorder sequence. - Two vectors (
postorder_seq
andinorder_seq
) to store the postorder and inorder sequences. - An unordered map (
val_to_index_map
) to map each value in the inorder sequence to its index, facilitating quick lookup.
- An integer (
Helper Function -
construct_subtree
:- This function is crucial for recursively constructing the binary tree. It takes two indices,
in_left
andin_right
, defining the current segment of the inorder sequence being processed. - Base Case: If
in_left
is greater thanin_right
, it returnsNULL
, indicating no subtree exists for this segment. - A root value is selected from
postorder_seq
usingcurrent_post_idx
and a new tree node is created with this value. - The index of this root value in the inorder sequence is found using
val_to_index_map
. - Recursively constructs the right subtree from the segment after the root’s index and the left subtree from the segment before the root’s index.
- The
current_post_idx
is decremented after selecting the root value to move backwards through the postorder sequence.
- This function is crucial for recursively constructing the binary tree. It takes two indices,
Function -
buildTree
:- Initializes the member variables with the provided
inorder
andpostorder
vectors. - Sets up the
val_to_index_map
with values and their corresponding indices from theinorder
sequence. - Invokes
construct_subtree
with the entire range of the inorder sequence to construct and return the root of the binary tree.
- Initializes the member variables with the provided
The approach is effective for reconstructing the binary tree as it efficiently leverages the unordered map for quick index lookups and recursively divides the problem into constructing subtrees. This ensures that each element from the postorder sequence is used exactly once as the root of a subtree, adhering to the nature of postorder traversal. This solution is well-suited for problems requiring tree reconstruction from traversal outputs, ensuring a time complexity approximately proportional to the number of nodes, given the unordered map operations average constant time complexity.
class TreeBuilder {
private int rootIndex;
private int[] postorderSeq;
private int[] inorderSeq;
private HashMap<Integer, Integer> indexMap = new HashMap<>();
public TreeNode buildHelper(int leftLimit, int rightLimit) {
if (leftLimit > rightLimit) {
return null;
}
int rootValue = postorderSeq[rootIndex];
TreeNode node = new TreeNode(rootValue);
int pivot = indexMap.get(rootValue);
rootIndex--;
node.right = buildHelper(pivot + 1, rightLimit);
node.left = buildHelper(leftLimit, pivot - 1);
return node;
}
public TreeNode constructTree(int[] inorder, int[] postorder) {
this.postorderSeq = postorder;
this.inorderSeq = inorder;
rootIndex = postorder.length - 1;
int index = 0;
for (int value : inorder) {
indexMap.put(value, index++);
}
return buildHelper(0, inorder.length - 1);
}
}
The Java solution provided constructs a binary tree from given inorder and postorder traversal arrays. Follow these steps to understand the code execution:
Initialize the
TreeBuilder
class which includes the necessary variables such asrootIndex
,postorderSeq
,inorderSeq
, andindexMap
for storing the traversal sequences and mapping the indices of inorder values.The
constructTree
method sets the sequences of postorder and inorder traversals. It initializesrootIndex
to point to the last element of the postorder array (which is the root of the tree). Populate theindexMap
with elements from the inorder array, where the key is the value of the node, and the value is its index in the inorder array.Execute
buildHelper
recursively to construct the binary tree. It accepts two parameters:leftLimit
andrightLimit
, which are initially set to the start and end of the inorder sequence, respectively. This method:- Checks if
leftLimit
exceedsrightLimit
, in which case the method returnsnull
indicating no subtree can be formed from this segment of the array. - Retrieves and removes the root node's value from
postorderSeq
usingrootIndex
and decreasesrootIndex
. - Identifies the pivot index of the current root in the inorder sequence using
indexMap
. - Recursively applies itself to construct the right and left subtrees. The right subtree is built first due to the nature of postorder traversal (left, right, root), and then the method progresses to constructing the left subtree.
- Checks if
The
TreeNode
class, utilized within this construction, must be defined outside of this snippet with at least the parametersint val; TreeNode left; TreeNode right;
.
This code efficiently reconstructs the binary tree by leveraging the properties of binary tree traversals, notably using hashmap for indexing and recursive subtree construction. Thus, the overall time complexity relates closely to O(n) due to the single pass approach in mapping and constructing the tree.
struct TreeNode* constructTree(int* InOrd, int InSize, int* PostOrd, int PostSize) {
if (InSize == 0) {
return NULL;
}
int index;
for (index = 0; index < InSize; index++) {
if (InOrd[index] == PostOrd[PostSize - 1]) {
break;
}
}
struct TreeNode* rootNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
rootNode->val = PostOrd[PostSize - 1];
rootNode->left = constructTree(InOrd, index, PostOrd, index);
rootNode->right = constructTree(InOrd + index + 1, InSize - index - 1, PostOrd + index, PostSize - index - 1);
return rootNode;
}
This solution demonstrates how to construct a binary tree from its inorder and postorder traversal arrays in C. Follow these steps to understand the implementation:
Check if the
InSize
(size of the inorder array) is zero. If it is, returnNULL
as it indicates that the tree or subtree has no elements.Initialize a local variable
index
to find the root node in the inorder array. This root is identified as the last element in the postorder arrayPostOrd[PostSize - 1]
.Iterate through the inorder array using a loop, comparing each element with the root value from the postorder array until it is found. Store this location in
index
.Allocate memory for a new
TreeNode
which becomes the root node of the tree or subtree. Set the value of this node toPostOrd[PostSize - 1]
(the root).Recursively construct the left subtree using the first segment of the inorder and postorder arrays up to the
index
.Similarly, construct the right subtree by invoking the function with the remaining elements of the inorder and postorder arrays, after excluding the elements used for the left subtree and the root.
Finally, return the
rootNode
which points to the constructed subtree or the complete tree based on the input arrays.
- This approach efficiently slices the problem into smaller subproblems, handling each subtree through recursive calls, and continuously building up the entire structure of the binary tree.
var constructTree = function(inorder, postorder) {
var indexMap = {};
var currentIndex = postorder.length - 1;
var build = function(left, right) {
if (left > right) return null;
var rootValue = postorder[currentIndex];
var rootNode = new TreeNode(rootValue);
var i = indexMap[rootValue];
currentIndex--;
rootNode.right = build(i + 1, right);
rootNode.left = build(left, i - 1);
return rootNode;
};
for (var i = 0; i < inorder.length; i++) indexMap[inorder[i]] = i;
return build(0, inorder.length - 1);
};
This JavaScript function constructs a binary tree using the given inorder and postorder traversal arrays. It utilizes the properties of these traversal methods to systematically rebuild the original tree. Here is a breakdown of how this implementation works:
- An
indexMap
object is created to store the indices of elements in theinorder
array, which helps in locating the roots quickly during tree construction. currentIndex
keeps track of the current index in thepostorder
array, starting from the last element, which is the root of the tree.- The
build
function is defined to construct the tree recursively. It acceptsleft
andright
parameters that delineate the current sub-array of the inorder array that the function is considering.- If
left
is greater thanright
, it indicates that there are no elements to construct the tree in this range, and hence returnsnull
. - It retrieves the value of the current root from
postorder
usingcurrentIndex
and decrementscurrentIndex
. - Using the value retrieved, it locates the index of this root in
inorder
throughindexMap
. - Recursively, it assigns the right child of the tree by considering the sub-array after this root index and the left child by considering the sub-array before this root index in
inorder
. - The function returns the constructed
rootNode
.
- If
- The indices of elements in
inorder
are initially stored inindexMap
. - The
build
function is first called with the full range of theinorder
array to commence the tree construction process.
By the end of the function execution, a binary tree based on the provided traversal arrays is constructed and returned.
class Solution:
def constructBinaryTree(self, in_order: List[int], post_order: List[int]) -> TreeNode:
def construct(in_start: int, in_end: int) -> TreeNode:
if in_start > in_end:
return None
# Select the last element from postorder as root
root_value = post_order.pop()
new_root = TreeNode(root_value)
# get the index of root in inorder list
root_index = in_order_map[root_value]
# Recursively construct right and then left subtree
new_root.right = construct(root_index + 1, in_end)
new_root.left = construct(in_start, root_index - 1)
return new_root
# Map to store the index of elements of inorder list
in_order_map = {value: index for index, value in enumerate(in_order)}
return construct(0, len(in_order) - 1)
To construct a binary tree from inorder and postorder traversal arrays using Python, follow these steps:
Start by creating a helper function,
construct
, that takes parametersin_start
andin_end
. These parameters define the current segment of the inorder array that needs to be processed.- Check the base condition where
in_start
is greater thanin_end
. If true, returnNone
, indicating no subtree can be formed from this segment. - Retrieve and remove the last element from the
post_order
list. This element represents the root of the current subtree. - Create a new tree node,
new_root
, with the retrieved root value.
- Check the base condition where
Retrieve the index of the current root value in the inorder traversal using a precomputed map,
in_order_map
.Recursively build the right subtree by calling the
construct
function with parameters(root_index + 1, in_end)
.- Recursively build the left subtree by calling the
construct
function with parameters(in_start, root_index - 1)
. - Return the
new_root
node. This node now points to a subtree with its correct left and right children constructed.
- Recursively build the left subtree by calling the
Before calling the helper function for the first time, preemptively build a map,
in_order_map
, where keys are elements fromin_order
list and values are their corresponding indexes. This map provides constant time complexity access to any element’s index in the inorder sequence to optimize the construction process.Finally, call the
construct
function with parameters0
andlen(in_order) - 1
to initiate the construction of the entire binary tree and return the result.
The process effectively breaks down the problem into smaller subproblems by determining a root from the postorder array and then locating this root in the inorder array to decide the boundaries of left and right subtrees. This approach efficiently constructs a binary tree from the given traversals by utilizing recursive tree construction and hashmap lookups.
No comments yet.