Construct Binary Tree from Inorder and Postorder Traversal
Building a binary tree from its inorder and postorder traversals can be done through a recursive approach.
Understand the Traversal Information:
- In the inorder traversal, left subtree nodes come before the root, and right subtree nodes come after the root.
- In the postorder traversal, the last element is the root of the current subtree, followed by the nodes of the left and right subtrees.
Start the Process:
- Start by picking the last element from the postorder array as the root.
- Find that root value in the inorder array. Elements on the left of this value in the inorder array form the left subtree, and elements on the right form the right subtree.
- Recursively repeat the process for the left and right subtrees.
Implement the Code:
|
|
Key Insights:
- Since the root is the last element in postorder, we start building the tree from the end of the postorder list.
- The inorder list is used to determine the boundary of the left and right subtrees.
- We build the right subtree first because in postorder, the right subtree elements appear before the left subtree elements.
The time complexity of this code is (O(n^2)) because the index
method takes (O(n)) time, and it is called (n) times. This can be optimized to (O(n)) by using a hash table to store the index of each element in the inorder array. The space complexity is (O(n)).
inorder = [-,-,-,-,-] postorder = [-,-,-,-,-]
Keep track of number of nodes we have created so far, stop when we have the same number of nodes as the input array.
Where does the root go when we do a post order traversal? Does the root always go to the last position for post order traversal? Yes. How do you decide the left child? We found the root as 3, look in the inorder and search for the root, the number left to the root is the left child.
How do you decide the right child? So for the right child, look in the post order and find the value to the left of the root. This is the right child.
In the inorder, the left value is 15 for 20 so 15 is the left child. In the postorder, the left value of 20 is 7, so 7 is the right child.
How do we know when we need to terminate?
Total number of nodes - number of leaf nodes 5 - 3 = 2 We need to know the number of leaves? How do we identify the leaves from the inorder and postorder arrays.
Return the TreeNode instance for 3.
Problem Definition
Define the Terms
Binary Tree: A tree that has at most two children (left and right child.
Define the Interface
Input: array of integers, array of integers
Output: TreeNode instance of binary tree
Identify Implicit Inputs
Define the Goal
Construct and return the binary tree
Identify the Constraints
1 <= inorder.length <= 3000 postorder.length == inorder.length -3000 <= inorder[i], postorder[i] <= 3000 inorder and postorder consist of unique values. Each value of postorder also appears in inorder. inorder is guaranteed to be the inorder traversal of the tree. postorder is guaranteed to be the postorder traversal of the tree.
Construct a Binary Tree
- Who is the root of the binary tree?
- A value for left and right children for the root.
Who is the root? What is its left child? What is its right child?
Determine the Scope
- List assumptions
- Define boundaries of the problem
Search the Problem Space
- Look for clues in the problem statement
Classify the Problem
Decontextualize the Problem
Can you think of this problem in a different way?
Can you reframe it?
Problem Representation
Analyze the Input and Output
Analyze the Examples
Solve the Problem by Hand
Recognize the Pattern
Identify the Invariants
Brainstorm Solutions
Brute Force Approach
Shortcomings
Recursive Approach Base Case: Not an edge case but a way to terminate recursion.
Helper function parameters: inorder,
left half: 0..i-1 (new inorder array) right half: i+1..size-1
Unit of Decomposition is variable in this case.
When the inorder array becomes empty, we terminate recursion.
Write two recursive calls (one for the left and one for the right)
Unit of Work
- Create an instance of TreeNode
- Create the left subtree (subproblem)
- Create the right subtree (subproblem)
- Root must be linked to the left subtree
- Root must be linked to the right subtree
What is the contract between the parent and the child? Output of the subproblems is a binary tree (left and right subtree) We can only get the constructed left and right subtrees after the recursive calls return.
So the links for the left and right must be done after the recursve calls return.
root.left = recur([0..i-1]) root.right = recur([i+1..size-1])
As we go from the leaves to the root. We are mixing declarative and imperative programming in one program.
What should we return from the helper function? We need to return the root object. Counter variable can be used to terminate the recursion.
- Evaluate and Select Approach
Analyze Time and Space Complexity
- Time: O( )
- Space: O( )
Outline the Solution
Key Takeaways
Reflect
What went right?
What went wrong?
What can we improve next time?
|
|
inorder = [-,-,-,-,-] postorder = [-,-,-,-,-]
Keep track of number of nodes we have created so far, stop when we have the same number of nodes as the input array.
Where does the root go when we do a post order traversal? Does the root always go to the last position for post order traversal? Yes. How do you decide the left child? We found the root as 3, look in the inorder and search for the root, the number left to the root is the left child.
How do you decide the right child? So for the right child, look in the post order and find the value to the left of the root. This is the right child.
In the inorder, the left value is 15 for 20 so 15 is the left child. In the postorder, the left value of 20 is 7, so 7 is the right child.
How do we know when we need to terminate?
Total number of nodes - number of leaf nodes 5 - 3 = 2 We need to know the number of leaves? How do we identify the leaves from the inorder and postorder arrays.
Return the TreeNode instance for 3.
Problem Definition
Define the Terms
Binary Tree: A tree that has at most two children (left and right child.
Define the Interface
Input: array of integers, array of integers
Output: TreeNode instance of binary tree
Identify Implicit Inputs
Define the Goal
Construct and return the binary tree
Identify the Constraints
1 <= inorder.length <= 3000 postorder.length == inorder.length -3000 <= inorder[i], postorder[i] <= 3000 inorder and postorder consist of unique values. Each value of postorder also appears in inorder. inorder is guaranteed to be the inorder traversal of the tree. postorder is guaranteed to be the postorder traversal of the tree.
Construct a Binary Tree
- Who is the root of the binary tree?
- A value for left and right children for the root.
Who is the root? What is its left child? What is its right child?
Determine the Scope
- List assumptions
- Define boundaries of the problem
Search the Problem Space
- Look for clues in the problem statement
Classify the Problem
Decontextualize the Problem
Can you think of this problem in a different way?
Can you reframe it?
Problem Representation
Analyze the Input and Output
Analyze the Examples
Solve the Problem by Hand
Recognize the Pattern
Identify the Invariants
Brainstorm Solutions
Brute Force Approach
Shortcomings
Recursive Approach Base Case: Not an edge case but a way to terminate recursion.
Helper function parameters: inorder,
left half: 0..i-1 (new inorder array) right half: i+1..size-1
Unit of Decomposition is variable in this case.
When the inorder array becomes empty, we terminate recursion.
Write two recursive calls (one for the left and one for the right)
Unit of Work
- Create an instance of TreeNode
- Create the left subtree (subproblem)
- Create the right subtree (subproblem)
- Root must be linked to the left subtree
- Root must be linked to the right subtree
What is the contract between the parent and the child? Output of the subproblems is a binary tree (left and right subtree) We can only get the constructed left and right subtrees after the recursive calls return.
So the links for the left and right must be done after the recursve calls return.
root.left = recur([0..i-1]) root.right = recur([i+1..size-1])
As we go from the leaves to the root. We are mixing declarative and imperative programming in one program.
What should we return from the helper function? We need to return the root object. Counter variable can be used to terminate the recursion.
- Evaluate and Select Approach
Outline the Solution
Key Takeaways
Reflect
What went right?
What went wrong?
What can we improve next time?
|
|
inorder = [-,-,-,-,-] postorder = [-,-,-,-,-]
Keep track of number of nodes we have created so far, stop when we have the same number of nodes as the input array.
Where does the root go when we do a post order traversal? Does the root always go to the last position for post order traversal? Yes. How do you decide the left child? We found the root as 3, look in the inorder and search for the root, the number left to the root is the left child.
How do you decide the right child? So for the right child, look in the post order and find the value to the left of the root. This is the right child.
In the inorder, the left value is 15 for 20 so 15 is the left child. In the postorder, the left value of 20 is 7, so 7 is the right child.
How do we know when we need to terminate?
Total number of nodes - number of leaf nodes 5 - 3 = 2 We need to know the number of leaves? How do we identify the leaves from the inorder and postorder arrays.
Return the TreeNode instance for 3.
Problem Definition
Define the Terms
Binary Tree: A tree that has at most two children (left and right child.
Define the Interface
Input: array of integers, array of integers
Output: TreeNode instance of binary tree
Identify Implicit Inputs
Define the Goal
Construct and return the binary tree
Identify the Constraints
1 <= inorder.length <= 3000 postorder.length == inorder.length -3000 <= inorder[i], postorder[i] <= 3000 inorder and postorder consist of unique values. Each value of postorder also appears in inorder. inorder is guaranteed to be the inorder traversal of the tree. postorder is guaranteed to be the postorder traversal of the tree.
Construct a Binary Tree
- Who is the root of the binary tree?
- A value for left and right children for the root.
Who is the root? What is its left child? What is its right child?
Determine the Scope
- List assumptions
- Define boundaries of the problem
Search the Problem Space
- Look for clues in the problem statement
Classify the Problem
Decontextualize the Problem
Can you think of this problem in a different way?
Can you reframe it?
Problem Representation
Analyze the Input and Output
Analyze the Examples
Solve the Problem by Hand
Recognize the Pattern
Identify the Invariants
Brainstorm Solutions
Brute Force Approach
Shortcomings
Recursive Approach Base Case: Not an edge case but a way to terminate recursion.
Helper function parameters: inorder,
left half: 0..i-1 (new inorder array) right half: i+1..size-1
Unit of Decomposition is variable in this case.
When the inorder array becomes empty, we terminate recursion.
Write two recursive calls (one for the left and one for the right)
Unit of Work
- Create an instance of TreeNode
- Create the left subtree (subproblem)
- Create the right subtree (subproblem)
- Root must be linked to the left subtree
- Root must be linked to the right subtree
What is the contract between the parent and the child? Output of the subproblems is a binary tree (left and right subtree) We can only get the constructed left and right subtrees after the recursive calls return.
So the links for the left and right must be done after the recursve calls return.
root.left = recur([0..i-1]) root.right = recur([i+1..size-1])
As we go from the leaves to the root. We are mixing declarative and imperative programming in one program.
What should we return from the helper function? We need to return the root object. Counter variable can be used to terminate the recursion.
- Evaluate and Select Approach
Analyze Time and Space Complexity
- Time: O( )
- Space: O( )
Outline the Solution
Key Takeaways
Reflect
What went right?
What went wrong?
What can we improve next time?
|
|
inorder = [-,-,-,-,-] postorder = [-,-,-,-,-]
Keep track of number of nodes we have created so far, stop when we have the same number of nodes as the input array.
Where does the root go when we do a post order traversal? Does the root always go to the last position for post order traversal? Yes. How do you decide the left child? We found the root as 3, look in the inorder and search for the root, the number left to the root is the left child.
How do you decide the right child? So for the right child, look in the post order and find the value to the left of the root. This is the right child.
In the inorder, the left value is 15 for 20 so 15 is the left child. In the postorder, the left value of 20 is 7, so 7 is the right child.
How do we know when we need to terminate?
Total number of nodes - number of leaf nodes 5 - 3 = 2 We need to know the number of leaves? How do we identify the leaves from the inorder and postorder arrays.
Return the TreeNode instance for 3.
Problem Definition
Define the Terms
Binary Tree: A tree that has at most two children (left and right child.
Define the Interface
Input: array of integers, array of integers
Output: TreeNode instance of binary tree
Identify Implicit Inputs
Define the Goal
Construct and return the binary tree
Identify the Constraints
1 <= inorder.length <= 3000 postorder.length == inorder.length -3000 <= inorder[i], postorder[i] <= 3000 inorder and postorder consist of unique values. Each value of postorder also appears in inorder. inorder is guaranteed to be the inorder traversal of the tree. postorder is guaranteed to be the postorder traversal of the tree.
Construct a Binary Tree
- Who is the root of the binary tree?
- A value for left and right children for the root.
Who is the root? What is its left child? What is its right child?
Determine the Scope
- List assumptions
- Define boundaries of the problem
Search the Problem Space
- Look for clues in the problem statement
Classify the Problem
Decontextualize the Problem
Can you think of this problem in a different way?
Can you reframe it?
Problem Representation
Analyze the Input and Output
Analyze the Examples
Solve the Problem by Hand
Recognize the Pattern
Identify the Invariants
Brainstorm Solutions
Brute Force Approach
Shortcomings
Recursive Approach Base Case: Not an edge case but a way to terminate recursion.
Helper function parameters: inorder,
left half: 0..i-1 (new inorder array) right half: i+1..size-1
Unit of Decomposition is variable in this case.
When the inorder array becomes empty, we terminate recursion.
Write two recursive calls (one for the left and one for the right)
Unit of Work
- Create an instance of TreeNode
- Create the left subtree (subproblem)
- Create the right subtree (subproblem)
- Root must be linked to the left subtree
- Root must be linked to the right subtree
What is the contract between the parent and the child? Output of the subproblems is a binary tree (left and right subtree) We can only get the constructed left and right subtrees after the recursive calls return.
So the links for the left and right must be done after the recursve calls return.
root.left = recur([0..i-1]) root.right = recur([i+1..size-1])
As we go from the leaves to the root. We are mixing declarative and imperative programming in one program.
What should we return from the helper function? We need to return the root object. Counter variable can be used to terminate the recursion.
- Evaluate and Select Approach
Analyze Time and Space Complexity
- Time: O( )
- Space: O( )
Outline the Solution
Key Takeaways
Reflect
What went right?
What went wrong?
What can we improve next time?
|
|
|
|