Binary Search Trees · 14 of 22
Count pairs from 2 BST whose sum is equal to given value X
Count pairs, one number from each of two sorted trees, that add up to x, by walking one tree from small to big and the other from big to small at the same time.
- Simple way
- time O(m*h2)
room O(h1+h2) - Clever way
- time O(m+n)
room O(h1+h2)
The problem, simply
You get two binary search trees (BSTs), A with m numbers and B with n numbers. Numbers inside one tree are all different. You also get a target x.
Count the pairs (a, b) where a is in A, b is in B, and a + b == x.
A story to remember it
Picture it
Tree A holds 2 to 8. Tree B holds 3, 6, 8, 10, 11, 15, 18. For x = 16 the matching pairs are 5 + 11, 6 + 10 and 8 + 8.
- answer
Examples
Three pairs
- In
A = [5, 3, 7, 2, 4, 6, 8], B = [10, 6, 15, 3, 8, 11, 18], x = 16- Out
3
5 + 11, 6 + 10 and 8 + 8. The same number may appear in both trees, as 8 does.
No pairs
- In
A = [2, 1, 3], B = [20, 10, 30], x = 5- Out
0
The biggest sum is 3 + 30 and the smallest is 1 + 10. 5 is below every sum.
Every number of A pairs up
- In
A = [2, 1, 3], B = [5, 4, 6], x = 7- Out
3
1 + 6, 2 + 5 and 3 + 4.
One tree is empty
- In
A = [], B = [1], x = 1- Out
0
No pairs can be made.
Way 1: the simple way
For every number a in A, search B for x - a. B is a BST, so each search walks one road.
- Visit every spot of A.
- Search B for
x - a(smaller goes left, bigger goes right). - If found, add 1 to the count.
class Solution {
public int countPairs(TreeNode a, TreeNode b, int x) {
if (a == null) return 0;
int here = contains(b, x - a.val) ? 1 : 0;
return here + countPairs(a.left, b, x) + countPairs(a.right, b, x);
}
private boolean contains(TreeNode node, int target) {
while (node != null) {
if (target == node.val) return true;
node = target < node.val ? node.left : node.right;
}
return false;
}
}How long it takes: m searches, each up to the height of B, O(m * h2). If B is a stick, that is O(m * n). Extra room: the recursion on A, O(h1).
Way 2: the clever way
If both trees were sorted lists, this would be the classic two finger trick: one finger at the small end of A, one at the big end of B. A BST is a sorted list in disguise, so walk it with a pile.
- Pile A walks A from smallest up: push its left road, and after each pop push the left road of the popped spot's right child.
- Pile B walks B from biggest down: push its right road, and after each pop push the right road of the popped spot's left child.
- Take
afrom A andbfrom B. Ifa + b == x, count it and take the next of both. If the sum is too small, take the nexta(bigger). If too big, take the nextb(smaller). - Stop when either pile runs out.
Seesaw for x = 16
01 / 10
Pile A gets the left road of A: 5, 3, 2. Pile B gets the right road of B: 10, 15, 18. Their tops are the smallest of A and the biggest of B.
- x
- 16
- count
- 0
- looking now
- seen
- answer
- path
- just added
- ignored
import java.util.*;
class Solution {
public int countPairs(TreeNode a, TreeNode b, int x) {
Deque<TreeNode> up = new ArrayDeque<>(); // A, smallest first
Deque<TreeNode> down = new ArrayDeque<>(); // B, biggest first
pushLeft(a, up);
pushRight(b, down);
int count = 0;
while (!up.isEmpty() && !down.isEmpty()) {
int sum = up.peek().val + down.peek().val;
if (sum == x) {
count++;
pushLeft(up.pop().right, up); // next a
pushRight(down.pop().left, down); // next b
} else if (sum < x) {
pushLeft(up.pop().right, up); // need a bigger a
} else {
pushRight(down.pop().left, down); // need a smaller b
}
}
return count;
}
private void pushLeft(TreeNode n, Deque<TreeNode> pile) {
while (n != null) { pile.push(n); n = n.left; }
}
private void pushRight(TreeNode n, Deque<TreeNode> pile) {
while (n != null) { pile.push(n); n = n.right; }
}
}How long it takes: every spot of both trees is pushed and popped at most once, O(m + n). Extra room: the two piles, each one road tall, O(h1 + h2).
Watch out for
- Walking both trees the same direction. Then a too-small sum has no move that is sure to help.
- Stopping when one pile is empty is right. With no
aleft there are no more pairs. - Sums can overflow
intfor huge values. Uselong sumif the numbers can be nearInteger.MAX_VALUE.
What interviewers ask next
- Use a hash set instead. Put all of A in a set, walk B and look up
x - b.O(m + n)time, butO(m)extra room. - Two numbers in one BST that add up to
x(LeetCode 653). Same two piles on the same tree, smallest up and biggest down, stopping when they meet. - Count pairs with sum at most
x. Whena + b <= x, every number in B up tobalso works witha, so this needs sizes or a different sweep. With sorted lists it is the usual two pointer count. - Three numbers from three trees. Fix each
afrom the first tree, then run this two pile walk on the other two.O(m * (n + p)).
Remember this
Grown-up words: the seesaw lines are the two pointer technique, walking a BST up or down with a pile is a BST iterator (forward and reverse inorder), and O(h1 + h2) is the height of the two piles.