Given two integer arrays, preorder
and postorder
where preorder
is the preorder traversal of a binary tree of distinct values and postorder
is the postorder traversal of the same tree, reconstruct and return the binary tree.
If there exist multiple answers, you can return any of them.
Example 1:
Input: preorder = [1,2,4,5,3,6,7], postorder = [4,5,2,6,7,3,1] Output: [1,2,3,4,5,6,7]
Example 2:
Input: preorder = [1], postorder = [1] Output: [1]
Constraints:
1 <= preorder.length <= 30
1 <= preorder[i] <= preorder.length
preorder
are unique.postorder.length == preorder.length
1 <= postorder[i] <= postorder.length
postorder
are unique.preorder
and postorder
are the preorder traversal and postorder traversal of the same binary tree.This problem involves reconstructing a binary tree given its preorder and postorder traversals. Both solutions presented utilize recursion, leveraging the inherent properties of these traversal types.
Key Properties of Preorder and Postorder Traversal:
Root -> Left Subtree -> Right Subtree
Left Subtree -> Right Subtree -> Root
This means the root of the entire tree is always the first element in the preorder traversal and the last element in the postorder traversal. This forms the basis for the recursive approach.
This solution employs a recursive helper function dfs
and a hashmap pos
.
Algorithm:
Hashmap Creation: A hashmap pos
is created to store the index of each element in the postorder
array. This allows for O(1) lookup time when searching for a node's position in the postorder traversal.
Recursive Function dfs(a, b, c, d)
:
a
, b
: Indices defining the range of the preorder traversal for the current subtree.c
, d
: Indices defining the range of the postorder traversal for the current subtree.The function performs the following:
a > b
(empty range), it returns null
.TreeNode
is created with the value preorder[a]
(the root of the current subtree).a == b
, the subtree consists of only the root node, so it's returned.preorder[a + 1]
. Its index in the postorder
array (i
) is found using the pos
hashmap.m
represents the number of nodes in the left subtree.dfs
is recursively called for the left and right subtrees using the calculated ranges.root
node of the constructed subtree is returned.Main Function Call: The dfs
function is initially called with the full ranges of the preorder and postorder arrays.
Time Complexity: O(n), where n is the number of nodes in the tree. Each node is visited once during the recursive calls.
Space Complexity: O(n) due to the recursive call stack and the hashmap pos
.
This solution also uses recursion but avoids using a hashmap. It achieves the same result by directly searching for the left subtree's root in the postorder traversal during each recursive call. This makes it slightly less efficient in terms of time complexity.
Algorithm:
The recursive function dfs(i, j, n)
works similarly to Solution 1:
n <= 0
) and single-node subtrees (n == 1
).TreeNode
with the value from the preorder traversal.postorder
array to find the index k
of the left subtree's root (preorder[i + 1]
).m
and n - m - 1
) are determined.Time Complexity: O(n^2) in the worst case. The linear search within the postorder
array in each recursive call contributes to the quadratic time complexity.
Space Complexity: O(n) due to the recursive call stack.
Code Examples (Python): The provided code snippets show implementations of both solutions in Python, as well as in other languages (Java, C++, Go, TypeScript). Solution 1 (with hashmap) is generally preferred due to its better time complexity.
In summary, both solutions effectively reconstruct the binary tree, but Solution 1 offers a significant performance advantage by using a hashmap for faster lookups. The choice between them depends on the specific constraints and performance requirements of the application.