Linked List · 11 of 36
Intersection of two Sorted Linked List
Two sorted chains of numbered boxes: build a brand new chain holding only the numbers that appear in both.
- Simple way
- time O(m + n)
room O(n) - Clever way
- time O(m + n)
room O(1)
The problem, simply
You get two linked lists, each sorted from small to big. Build a new list with the numbers that are in both lists, also sorted. Do not change the two input lists: the answer must be made of new boxes.
If a number repeats, each box can be matched only once. So 1 1 2 and 1 1 1 share two 1s. Some versions want each common number only once; that is a one line change, shown below.
A story to remember it
Picture it
List a is 1 2 3 4 6, list b is 2 4 6 8. The green boxes are in both: 2, 4 and 6.
- answer
Examples
A normal case
- In
a = 1 2 3 4 6, b = 2 4 6 8- Out
2 -> 4 -> 6
Three numbers are in both lists.
One match
- In
a = 10 20 40 50, b = 15 40- Out
40
Only 40 is shared. Once b runs out, we stop even though a has 50 left.
Nothing shared
- In
a = 1 2 3, b = 4 5 6- Out
null
Return an empty list, not a crash.
Repeats
- In
a = 1 1 2 3, b = 1 1 3- Out
1 -> 1 -> 3
Two 1s in each list, so two matches. If the problem asks for distinct values, the answer is 1 -> 3. Ask which one is wanted.
One list empty
- In
a = 1 2, b = empty- Out
null
Nothing can be in both.
Way 1: the simple way
Forget that the lists are sorted. Count what is in b, then walk a and take what is still available.
- Walk
band count each number in a map. - Walk
a. If the count of the number is more than 0, add a new box with it to the answer and lower the count.
b counted into a map. Walking a: 2, 4 and 6 have a count above 0, so they go into the answer.
- answer
- just added
class Solution {
public static Node findIntersection(Node head1, Node head2) {
Map<Integer, Integer> count = new HashMap<>();
for (Node p = head2; p != null; p = p.next) count.merge(p.data, 1, Integer::sum);
Node dummy = new Node(0), tail = dummy;
for (Node p = head1; p != null; p = p.next) {
int c = count.getOrDefault(p.data, 0);
if (c > 0) {
tail.next = new Node(p.data); // a new box, inputs stay untouched
tail = tail.next;
count.put(p.data, c - 1); // each box of b is used once
}
}
return dummy.next;
}
}How long it takes: one walk over each list, O(m + n). Extra room: the map can hold every number of b, O(n). It works even for unsorted lists, but it wastes the sorted order.
Way 2: the clever way
Use the sticker album trick with two pointers. The sorted order tells us which finger can safely move.
- Make a dummy box and a
tailfinger on it. New boxes hang aftertail. - While both
aandbare on a box: ifa.data == b.data, hang a new box with that number and movea,bandtail. - If
a.data < b.data, movea. Otherwise moveb. - Return
dummy.next.
Two fingers walk two sorted lists
01 / 07
a and b start at the heads. The answer starts with a dummy box d, and tail sits on it, ready to hang new boxes.
- looking now
- checking
- done
- answer
- rejected
- just added
- ignored
class Solution {
public static Node findIntersection(Node head1, Node head2) {
Node dummy = new Node(0), tail = dummy; // dummy saves a special case for the first box
Node a = head1, b = head2;
while (a != null && b != null) {
if (a.data == b.data) {
tail.next = new Node(a.data);
tail = tail.next;
a = a.next;
b = b.next;
} else if (a.data < b.data) {
a = a.next; // a is too small to ever match
} else {
b = b.next; // b is too small to ever match
}
}
return dummy.next;
}
}For distinct values only, change the match line to add the box only when tail == dummy || tail.data != a.data.
How long it takes: each step moves at least one finger, so at most m + n steps, O(m + n). Extra room: a few fingers, O(1), not counting the answer list that we must build anyway.
Watch out for
- Moving only one finger after a match. Then the same box gets matched again and you get extra copies.
- Stopping too late. As soon as either list ends, nothing more can match.
- Forgetting to ask about repeats. Matching each box once and listing each value once give different answers on
1 1 3. - Returning
dummyinstead ofdummy.next.
What interviewers ask next
- Union of two sorted lists. Same walk, but take the smaller value each step and take both tails at the end. That is the merge step of merge sort.
- The lists are not sorted. Use Way 1 with a hash map, or sort both with merge sort first,
O(n log n). - One list is much longer than the other. Walk the short list and binary search in the long one. With an array that is
O(m log n), but a linked list has no random access, so the two pointers are still best. - Intersect
ksorted lists. Intersect them two at a time, smallest first, so the answer shrinks quickly. - Intersection point of two lists that share boxes. That is a different problem: it is about the same box, not the same number.
Remember this
Grown-up words: the sticker albums are sorted linked lists, the fingers are two pointers, the dummy box is a sentinel node, tail is the tail pointer of the answer, and matching each box once is a multiset intersection.