Linked List · 22 of 36
Count triplets in a sorted DLL whose sum is equal to given value X
Count the groups of three boxes in a sorted two way chain whose numbers add up to x, by fixing one box and squeezing the rest from both ends.
- Simple way
- time O(n^3)
room O(1) - Clever way
- time O(n^2)
room O(1)
The problem, simply
You get a sorted doubly linked list with no repeated numbers, and a number x. Count how many groups of three different boxes add up to exactly x. The order inside a group does not matter, so (2, 6, 9) and (9, 2, 6) are the same group.
A story to remember it
Picture it
A sorted doubly linked list. With x = 17 there are two groups: (2, 6, 9) and (4, 5, 8).
- answer
Examples
A normal case
- In
1 2 4 5 6 8 9, x = 17- Out
2
The groups are (2, 6, 9) and (4, 5, 8).
Many groups
- In
1 2 4 5 6 8 9, x = 15- Out
5
(1, 5, 9), (1, 6, 8), (2, 4, 9), (2, 5, 8) and (4, 5, 6). It is easy to miss some by hand, which is why a careful method matters.
Exactly three boxes
- In
1 2 3, x = 6- Out
1
The only group is all three boxes.
Too few boxes
- In
5 9, x = 14- Out
0
Two boxes cannot make a group of three.
Way 1: the simple way
Try every group of three.
- Finger
awalks every box. - Finger
bwalks every box aftera. - Finger
cwalks every box afterb. - If the three numbers add up to
x, count it.
One of many tries: a on 2, b on 6, c on 9. That adds up to 17, so count it. The three fingers try every such group.
- answer
class Solution {
static int countTriplets(Node head, int x) {
int count = 0;
for (Node a = head; a != null; a = a.next)
for (Node b = a.next; b != null; b = b.next)
for (Node c = b.next; c != null; c = c.next)
if (a.data + b.data + c.data == x) count++;
return count;
}
}How long it takes: about n * n * n / 6 groups, O(n^3). Extra room: three fingers, O(1).
Way 2: the clever way
Fix the first box with i. The other two must add up to need = x - i.data, and they must come after i. Find them with the two pointer squeeze from the pairs problem. The back arrows let right walk left from the tail.
- Walk to the tail once.
- For each box
i: putleftoni.nextandrighton the tail. - While
leftis beforeright: ifleft + right == need, count it and move both inward. If the sum is too small, moveleftforward. If too big, moverightback. - Move
iforward and repeat.
Fix one box, squeeze the rest from both ends
01 / 15
Fix the first box with i. Then hunt for two boxes after it, with left and right, that add up to 17 minus box i.
- x
- 17
- count
- 0
- looking now
- checking
- answer
- ignored
class Solution {
static int countTriplets(Node head, int x) {
if (head == null) return 0;
Node tail = head;
while (tail.next != null) tail = tail.next; // walk to the end once
int count = 0;
for (Node i = head; i != null && i.next != null; i = i.next) {
int need = x - i.data;
Node left = i.next, right = tail;
while (left != right && right.next != left) { // stop when they meet or cross
int sum = left.data + right.data;
if (sum == need) {
count++;
left = left.next;
right = right.prev;
} else if (sum < need) {
left = left.next; // too light
} else {
right = right.prev; // too heavy
}
}
}
return count;
}
}How long it takes: for each of the n choices of i, the squeeze takes at most n steps, O(n^2). Extra room: four fingers, O(1).
Watch out for
- Starting
leftat the head instead ofi.next. Then a box can be used twice, or the same group is counted from differenti. - Duplicate values. The classic version promises distinct values. With repeats, after a match you must count runs of equal values on both sides, and skip equal values of
i. - Fewer than three boxes. The loops handle it and return 0, but say it out loud.
What interviewers ask next
- Can you do better than
O(n^2)? Not in general. This is the 3SUM problem, and no one knows a much faster way for it. - Use a hash map instead. Put every value in a map from value to node, then for each pair
(a, b)withabeforeblook upx - a - band count it only if it comes afterb. That isO(n^2)time butO(n)extra room, so the two pointer way is better here. - Return the groups instead of counting them. Save
(i, left, right)when you match. - Four numbers (4SUM). Fix two boxes with two loops and squeeze the rest,
O(n^3). - The list is not sorted. Sort it first with merge sort for linked lists,
O(n log n), then do the same thing.
Remember this
Grown-up words: the line of kids is a sorted doubly linked list, the pick is the fixed first element, the seesaw game is the two pointer technique, and the whole problem is 3SUM.