You are given the roots of two Binary Search Trees (BSTs):
root1, root2
Your task:
Return a sorted list containing all elements from both trees.
Example:
Input: root1 = [2,1,4] root2 = [1,0,3] Output: [0,1,1,2,3,4]
Another example:
Input: root1 = [] root2 = [5,4,7] Output: [4,5,7]
Problem Understanding
Important characteristics:
- Both trees are BSTs
- BST property:
In-order traversal returns sorted elements - We must combine values from both trees
- Final output must be globally sorted
- Trees may have different sizes
- Trees may contain overlapping values
So the challenge reduces to:
Extract sorted lists from both BSTs, then merge them.
This is identical to merging two sorted arrays.
Logic Explained in Simple English
The simplest way to think about solving this:
- Perform in-order traversal on the first tree to collect elements in sorted order.
- Perform in-order traversal on the second tree to collect elements in sorted order.
- Now you have:
list1 sorted list2 sorted - Merge them like in merge step of merge sort:
- Compare front elements
- Append smaller one
- Move pointer forward
- Continue until both lists are consumed
Why this works:
- In-order traversal guarantees sorted output for BST
- Merging two sorted lists takes linear time
- Overall efficiency is optimal
Alternative thought:
You could push both into one list and sort — but that’s unnecessarily slower.
Step-by-Step Approach
- Initialize two empty lists: list1 and list2
- In-order traverse root1, store into list1
- In-order traverse root2, store into list2
- Merge list1 and list2 into result list
- Return result
Edge cases handled naturally:
- If one tree is empty → result is the other list
- If both empty → return empty list
Java Implementation
class Solution {
public List<Integer> getAllElements(TreeNode root1, TreeNode root2) {
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
inorder(root1, list1);
inorder(root2, list2);
return merge(list1, list2);
}
private void inorder(TreeNode root, List<Integer> list) {
if (root == null) return;
inorder(root.left, list);
list.add(root.val);
inorder(root.right, list);
}
private List<Integer> merge(List<Integer> list1, List<Integer> list2) {
List<Integer> result = new ArrayList<>();
int i = 0, j = 0;
while (i < list1.size() && j < list2.size()) {
if (list1.get(i) <= list2.get(j)) {
result.add(list1.get(i++));
} else {
result.add(list2.get(j++));
}
}
while (i < list1.size()) {
result.add(list1.get(i++));
}
while (j < list2.size()) {
result.add(list2.get(j++));
}
return result;
}
}
Dry Run Example
Input:
root1 = [2,1,4] root2 = [1,0,3]
Step 1 — In-order traversal results:
Tree 1:
[1,2,4]
Tree 2:
[0,1,3]
Step 2 — Merge them:
Compare:
0 < 1 → result = [0]
1 ≤ 1 → result = [0,1]
1 < 2 → result = [0,1,1]
2 < 3 → result = [0,1,1,2]
3 < 4 → result = [0,1,1,2,3]
Append remaining 4 → result = [0,1,1,2,3,4]
Final output:
[0,1,1,2,3,4]
Time and Space Complexity
Time Complexity
O(m + n)
Where:
- m = number of nodes in root1
- n = number of nodes in root2
Reason:
- Traversing both trees costs O(m+n)
- Merging lists costs O(m+n)
Space Complexity
O(m + n)
To store both traversal lists and result.
Common Mistakes and How to Avoid Them
Mistake 1: Sorting after combining lists
This leads to:
O((m+n) log (m+n)) — slower than needed
Mistake 2: Not using BST property
In-order traversal MUST be used.
Mistake 3: Using recursion without null checks
Always check root for null.
Mistake 4: Merging incorrectly by skipping equality case
Use <= to preserve ordering stability.
Mistake 5: Trying to modify trees
No need — collect values only.
