Construct Binary Tree from Inorder and Postorder Traversal
MedPrompt
Given two integer arrays inorder and postorder where inorder is the inorder traversal of a binary tree and postorder is the postorder traversal of the same tree, construct and return the binary tree.
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 <= 3000postorder.length == inorder.length-3000 <= inorder[i], postorder[i] <= 3000inorderandpostorderconsist of unique values.- Each value of
postorderalso appears ininorder. inorderis guaranteed to be the inorder traversal of the tree.postorderis guaranteed to be the postorder traversal of the tree.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach uses a straightforward recursive strategy. The core idea relies on the properties of postorder and inorder traversals. The last element in a postorder traversal is the root of the tree. Once the root is identified, we can find its position in the inorder traversal. All elements to the left of the root in the inorder traversal belong to the left subtree, and all elements to the right belong to the right subtree. This allows us to partition the problem and recursively build the left and right subtrees. The main drawback is the need to perform a linear scan of the inorder array in each recursive step to find the root's index, which leads to a quadratic time complexity in the worst case.
Algorithm
- The main function
buildTreeinitializes the process by calling a recursive helper function with the full range of bothinorderandpostorderarrays. - The recursive helper function
buildHelper(inorder, inStart, inEnd, postorder, postStart, postEnd)works on the subarrays defined by the start and end indices. - Base Case: If the start index is greater than the end index for either array, it means the subarray is empty, and we return
null. - Identify Root: The root of the current subtree is always the last element of the current
postordersubarray (postorder[postEnd]). A newTreeNodeis created with this value. - Find Root in Inorder: A linear search is performed on the current
inordersubarray (frominStarttoinEnd) to find the index of the root's value. Let's call thisrootIndex. - Partition Subtrees:
- The elements to the left of
rootIndexin theinorderarray (inStarttorootIndex - 1) belong to the left subtree. - The elements to the right of
rootIndex(rootIndex + 1toinEnd) belong to the right subtree.
- The elements to the left of
- Calculate Left Subtree Size: The number of nodes in the left subtree is calculated as
leftSubtreeSize = rootIndex - inStart. - Recursive Calls:
- The left child is constructed by a recursive call with the corresponding
inorderandpostordersubarrays for the left subtree. - The right child is constructed similarly with the subarrays for the right subtree.
- The left child is constructed by a recursive call with the corresponding
- Return Node: The constructed node with its left and right children attached is returned.
Walkthrough
The algorithm is implemented using a recursive helper function that takes the start and end indices for the current segments of the inorder and postorder arrays. In each call, we first identify the root from the end of the postorder segment. Then, we iterate through the inorder segment to locate this root. This location tells us the boundary between the left and right subtrees. We can also determine the size of the left subtree, which helps in partitioning the postorder array for the subsequent recursive calls. The function then recursively calls itself to build the left and right children and connects them to the root.
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */class Solution { public TreeNode buildTree(int[] inorder, int[] postorder) { if (inorder == null || postorder == null || inorder.length == 0) { return null; } return buildHelper(inorder, 0, inorder.length - 1, postorder, 0, postorder.length - 1); } private TreeNode buildHelper(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd) { // Base case: if the subarray is empty if (inStart > inEnd || postStart > postEnd) { return null; } // The last element in the current postorder segment is the root int rootVal = postorder[postEnd]; TreeNode root = new TreeNode(rootVal); // Find the root's index in the inorder array (Linear Search) int rootIndex = -1; for (int i = inStart; i <= inEnd; i++) { if (inorder[i] == rootVal) { rootIndex = i; break; } } // Calculate the size of the left subtree int leftSubtreeSize = rootIndex - inStart; // Recursively build the left subtree root.left = buildHelper(inorder, inStart, rootIndex - 1, postorder, postStart, postStart + leftSubtreeSize - 1); // Recursively build the right subtree root.right = buildHelper(inorder, rootIndex + 1, inEnd, postorder, postStart + leftSubtreeSize, postEnd - 1); return root; }}Complexity
Time
O(N^2)
Space
O(N)
Trade-offs
Pros
Relatively simple to understand and implement.
Follows the definition of traversals directly.
Cons
The time complexity of O(N^2) is inefficient for large inputs.
Repeatedly scanning the inorder array is a redundant operation.
Solutions
Solution
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { private Map < Integer , Integer > indexes = new HashMap <>(); public TreeNode buildTree ( int [] inorder , int [] postorder ) { for ( int i = 0 ; i < inorder . length ; ++ i ) { indexes . put ( inorder [ i ], i ); } return dfs ( inorder , postorder , 0 , 0 , inorder . length ); } private TreeNode dfs ( int [] inorder , int [] postorder , int i , int j , int n ) { if ( n <= 0 ) { return null ; } int v = postorder [ j + n - 1 ]; int k = indexes . get ( v ); TreeNode root = new TreeNode ( v ); root . left = dfs ( inorder , postorder , i , j , k - i ); root . right = dfs ( inorder , postorder , k + 1 , j + k - i , n - k + i - 1 ); return root ; } }Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.