The simplest approach is to collect all values from both trees and check every possible pair. If any pair sums to the target, we have found our answer.
a in the first list and each value b in the second list, check if a + b == target.true if a valid pair is found, false otherwise.class Solution:
def twoSumBSTs(self, root1: Optional[TreeNode], root2: Optional[TreeNode], target: int) -> bool:
def dfs(curr_node, node_list):
if not curr_node:
return
node_list.append(curr_node.val)
dfs(curr_node.left, node_list)
dfs(curr_node.right, node_list)
node_list1, node_list2 = [], []
dfs(root1, node_list1)
dfs(root2, node_list2)
for a in node_list1:
for b in node_list2:
if a + b == target:
return True
return FalseWhere and are the number of nodes in the two trees.
Since the second tree is a BST, we can leverage its sorted structure. For each node in the first tree, we compute the complement (target - node.val) and use binary search to check if that complement exists in the second tree.
dfs.v, compute complement = target - v.complement, return true.false.class Solution:
def twoSumBSTs(self, root1: Optional[TreeNode], root2: Optional[TreeNode], target: int) -> bool:
def binarySearch(root2, target2):
if not root2:
return False
if root2.val == target2:
return True
elif root2.val > target2:
return binarySearch(root2.left, target2)
else:
return binarySearch(root2.right, target2)
def dfs(root, target):
if not root:
return False
if binarySearch(root2, target - root.val):
return True
return dfs(root.left, target) or dfs(root.right, target)
return dfs(root1, target)Where and are the number of nodes in the two trees.
We can trade space for time by storing all values from one tree in a hash set. Then for each value in the other tree, we check if the complement exists in the set in O(1) time.
target - value exists in the second set.true if found, false otherwise.class Solution:
def twoSumBSTs(self, root1: Optional[TreeNode], root2: Optional[TreeNode], target: int) -> bool:
def dfs(curr_node, node_set):
if not curr_node:
return
dfs(curr_node.left, node_set)
node_set.add(curr_node.val)
dfs(curr_node.right, node_set)
node_set1, node_set2 = set(), set()
dfs(root1, node_set1)
dfs(root2, node_set2)
for value1 in node_set1:
if target - value1 in node_set2:
return True
return FalseWhere and are the number of nodes in the two trees.
An inorder traversal of a BST produces a sorted list. If we have sorted lists from both trees, we can use the classic two-pointer technique: one pointer starts at the beginning of the first list (smallest), and another starts at the end of the second list (largest). We adjust pointers based on whether the current sum is too small or too large.
pointer1 = 0 (start of first list) and pointer2 = len(list2) - 1 (end of second list).target, return true.target, increment pointer1.target, decrement pointer2.false if no pair is found.class Solution:
def twoSumBSTs(self, root1: Optional[TreeNode], root2: Optional[TreeNode], target: int) -> bool:
def dfs(curr_node, node_list):
if not curr_node:
return
dfs(curr_node.left, node_list)
node_list.append(curr_node.val)
dfs(curr_node.right, node_list)
node_list1, node_list2 = [], []
dfs(root1, node_list1)
dfs(root2, node_list2)
pointer1 = 0
pointer2 = len(node_list2) - 1
while pointer1 < len(node_list1) and pointer2 >= 0:
if node_list1[pointer1] + node_list2[pointer2] == target:
return True
elif node_list1[pointer1] + node_list2[pointer2] < target:
pointer1 += 1
else:
pointer2 -= 1
return FalseWhere and are the number of nodes in the two trees.
The two-pointer approach requires O(m + n) space to store the sorted lists. Morris traversal lets us iterate through a BST in sorted order using O(1) extra space by temporarily modifying tree pointers. We use forward Morris traversal on one tree and reverse Morris traversal on the other to simulate the two-pointer technique without extra space.
target, return true.target, advance the forward iterator.target, advance the reverse iterator.false if no pair is found.class Solution:
def twoSumBSTs(self, root1: Optional[TreeNode], root2: Optional[TreeNode], target: int) -> bool:
def morris_traversal(root):
current = root
while current:
if not current.left:
yield current.val
current = current.right
else:
pre = current.left
while pre.right and pre.right != current:
pre = pre.right
if not pre.right:
pre.right = current
current = current.left
else:
pre.right = None
yield current.val
current = current.right
def reversed_morris_traversal(root):
current = root
while current:
if not current.right:
yield current.val
current = current.left
else:
pre = current.right
while pre.left and pre.left != current:
pre = pre.left
if not pre.left:
pre.left = current
current = current.right
else:
pre.left = None
yield current.val
current = current.left
iterater1 = morris_traversal(root1)
iterater2 = reversed_morris_traversal(root2)
value1 = next(iterater1, None)
value2 = next(iterater2, None)
while value1 is not None and value2 is not None:
if value1 + value2 == target:
return True
elif value1 + value2 < target:
value1 = next(iterater1, None)
else:
value2 = next(iterater2, None)
return FalseWhere and are the number of nodes in the two trees.
A common mistake is ignoring the BST property and treating both trees as generic binary trees. This leads to inefficient solutions that don't leverage the sorted structure for binary search or two-pointer approaches. Always consider whether the BST ordering can help optimize your search.
When searching for a pair that sums to the target, some forget to compute target - value correctly or accidentally search for the wrong value. For example, if target = 9 and the current node has value 4, you need to search for 5 in the other tree, not 9 - 4 = 5 with any other formula.
Morris traversal temporarily modifies tree pointers to achieve O(1) space. A pitfall is forgetting to restore the original tree structure after traversal or exiting early without cleanup. This can corrupt the tree for subsequent operations or cause infinite loops.