08. Construct Tree from Preorder & Postorder
β GFG solution to the Construct Tree from Preorder & Postorder problem: build a full binary tree from preorder and postorder traversals using recursive approach with optimized lookups. π
The problem can be found at the following link: π Question Link
π§© Problem Description
Given two arrays pre[] and post[] that represent the preorder and postorder traversals of a full binary tree, your task is to construct the binary tree and return its root.
A full binary tree is a binary tree where every node has either 0 or 2 children. The preorder and postorder traversals contain unique values, and every value present in the preorder traversal is also found in the postorder traversal.
π Examples
Example 1
Input: pre[] = [1, 2, 4, 8, 9, 5, 3, 6, 7], post[] = [8, 9, 4, 5, 2, 6, 7, 3, 1]
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
Explanation: The tree structure is:
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9Example 2
π Constraints
$1 \le \text{number of nodes} \le 10^3$
$1 \le \text{pre}[i], \text{post}[i] \le 10^4$
β
My Approach
The optimal approach uses recursive tree construction with postorder boundary tracking:
Recursive Construction with Postorder Search
Understanding Traversal Properties:
In preorder: Root β Left Subtree β Right Subtree
In postorder: Left Subtree β Right Subtree β Root
The first element in preorder is always the root
The last element in postorder is always the root
Key Insight:
After identifying the root from preorder, the next element is the root of the left subtree
Find this left subtree root in postorder to determine the boundary between left and right subtrees
Algorithm Steps:
Use a global index pointer to track current position in preorder array
Create root node with current preorder element and increment index
If subtree is not a leaf (l β r) and more nodes exist:
Find the position of next preorder element (left child) in postorder within current range
Recursively build left subtree from l to pos
Recursively build right subtree from pos+1 to r-1
Return the constructed root
Base Case:
When left boundary equals right boundary (l == r), we have a leaf node
When index reaches end of preorder array, no more nodes to process
π Time and Auxiliary Space Complexity
Expected Time Complexity: O(nΒ²), where n is the number of nodes in the tree. In the worst case, for each node we perform a linear search in the postorder array to find the left child position, resulting in O(n) operations per node.
Expected Auxiliary Space Complexity: O(h), where h is the height of the tree. This space is used by the recursion call stack. In the worst case of a skewed tree, h can be O(n), but for a balanced full binary tree, h = O(log n).
π§βπ» Code (C++)
β‘ View Alternative Approaches with Code and Analysis
π 2οΈβ£ HashMap with Index Mapping
π‘ Algorithm Steps:
Create a HashMap to store postorder element indices for O(1) lookup.
Use recursive function with preorder index pointer and postorder boundaries.
Root is always the current preorder element, increment pointer after creating node.
Left child root is next preorder element, find its position in postorder to determine subtree size.
π Complexity Analysis:
Time: β±οΈ O(n) - Single pass with O(1) lookups
Auxiliary Space: πΎ O(n) - HashMap storage for postorder indices
β
Why This Approach?
Fast constant time lookups eliminate repeated searches
Cleaner code with preprocessing step
Standard approach for tree construction problems
π 3οΈβ£ Stack-Based Iterative
π‘ Algorithm Steps:
Use stack to track current path from root to current node being processed.
Iterate through preorder array and create nodes sequentially.
Match postorder elements with stack top to determine when subtrees complete.
Pop from stack when current node matches postorder element indicating subtree completion.
π Complexity Analysis:
Time: β±οΈ O(n) - Single pass through arrays
Auxiliary Space: πΎ O(h) - Stack space for tree height
β
Why This Approach?
Avoids recursion overhead with iterative solution
Space efficient using only stack for current path
Single forward pass through both arrays
π 4οΈβ£ Range-Based Recursive
π‘ Algorithm Steps:
Track current range in both preorder and postorder arrays simultaneously.
Root is first element in current preorder range.
Find root's left child (next preorder element) in postorder to split ranges.
Recursively build left subtree then right subtree with updated ranges.
π Complexity Analysis:
Time: β±οΈ O(nΒ²) - Linear search in each recursive call
Auxiliary Space: πΎ O(h) - Recursion stack depth
β
Why This Approach?
Explicit range tracking for clear boundary management
No preprocessing required
Intuitive divide and conquer approach
π π Comparison of Approaches
π Approach
β±οΈ Time Complexity
πΎ Space Complexity
β Pros
β οΈ Cons
π Direct Search
π‘ O(nΒ²)
π’ O(h)
π― No preprocessing needed
π Repeated linear searches
πΊοΈ HashMap Mapping
π’ O(n)
π‘ O(n)
π Fast O(1) lookups
πΎ Extra space for HashMap
π Stack Iterative
π’ O(n)
π’ O(h)
β No recursion overhead
π§ Complex pointer manipulation
π Range Recursive
π‘ O(nΒ²)
π’ O(h)
π Clear boundary tracking
π Slower without optimization
π Best Choice Recommendation
π― Scenario
ποΈ Recommended Approach
π₯ Performance Rating
π Optimal time complexity
π₯ HashMap Mapping
β β β β β
πΎ Space optimization priority
π₯ Stack Iterative
β β β β β
π Code simplicity
π₯ Direct Search
β β β ββ
π― Interview/Competitive
π HashMap Mapping
β β β β β
β Code (Java)
π Code (Python)
π§ Contribution and Support
For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: π¬ Any Questions?. Let's make this learning journey more collaborative!
β If you find this helpful, please give this repository a star! β
πVisitor Count
Last updated