Linked List · 29 of 36
Sort a LL of 0s, 1s and 2s
Sort a chain that only holds 0s, 1s and 2s by sending each box to one of three little lines and then joining the lines in order.
- Simple way
- time O(n)
room O(1) - Clever way
- time O(n)
room O(1)
The problem, simply
You get a linked list where every box holds a 0, a 1 or a 2. Sort it so all the 0s come first, then the 1s, then the 2s. Give back the new head.
There are only three kinds of numbers, so you never need a real comparison sort. The question is whether you copy numbers or move boxes.
A story to remember it
Picture it
A jumbled chain of 0s, 1s and 2s.
Examples
A normal case
- In
2 -> 1 -> 2 -> 0 -> 1 -> 0 -> 2- Out
0 -> 0 -> 1 -> 1 -> 2 -> 2 -> 2
Two 0s, two 1s and three 2s.
No 1s at all
- In
2 -> 0 -> 2 -> 0- Out
0 -> 0 -> 2 -> 2
The ones line is empty, so the end of the zeros must hook straight to the twos. This is the case people get wrong.
All the same
- In
1 -> 1 -> 1- Out
1 -> 1 -> 1
Only one line gets boxes. The answer is that line.
Reverse order
- In
2 -> 1 -> 0- Out
0 -> 1 -> 2
Every box moves.
Empty
- In
null- Out
null
Nothing to sort.
Way 1: the simple way
Count, then overwrite.
- Walk the chain and count how many 0s, 1s and 2s there are.
- Walk again from the head. Write 0 into the first
count0boxes, then 1 into the nextcount1boxes, then 2 into the rest.
The counts after one walk. Now the boxes are written over from the head: two 0s, two 1s, three 2s.
class Solution {
public Node segregate(Node head) {
int[] count = new int[3];
for (Node cur = head; cur != null; cur = cur.next) count[cur.data]++;
Node cur = head;
for (int d = 0; d < 3; d++) {
for (int i = 0; i < count[d]; i++) { // write d, count[d] times
cur.data = d;
cur = cur.next;
}
}
return head;
}
}How long it takes: two walks, O(n). Extra room: three counters, O(1). This is often the expected answer for this exact problem. But if each box carries more than a number (a name, a record), overwriting the number would mix up the records, so interviewers then ask for the next way.
Way 2: the clever way
Move the real boxes into three lines, then join them.
- Make three dummy boxes, one per line, and a tail finger for each:
zero,one,two. - Walk the chain. Hook each box to the end of its line and move that tail.
- Join: the end of the zeros points to the first 1, or to the first 2 if there are no 1s. The end of the ones points to the first 2.
- Set the end of the twos to
null. - Give back the box after the zeros dummy.
Three bins, then one chain
01 / 10
Three empty lines wait, each with a dummy box in front (not drawn). curr is on the first box.
- looking now
- answer
- just added
class Solution {
public Node segregate(Node head) {
Node zeroHead = new Node(0), oneHead = new Node(0), twoHead = new Node(0);
Node zero = zeroHead, one = oneHead, two = twoHead; // tails of the three lines
for (Node cur = head; cur != null; cur = cur.next) {
if (cur.data == 0) { zero.next = cur; zero = cur; }
else if (cur.data == 1) { one.next = cur; one = cur; }
else { two.next = cur; two = cur; }
}
zero.next = (oneHead.next != null) ? oneHead.next : twoHead.next; // skip an empty ones line
one.next = twoHead.next;
two.next = null; // cut the old arrow
return zeroHead.next; // works even with no 0s
}
}How long it takes: one walk, O(n). Extra room: three dummy boxes and three tails, O(1). No number is overwritten, and boxes with the same number keep their old order.
Watch out for
- Forgetting
two.next = null. The last 2 still points to its old neighbor, and the chain loops. - Returning
head. The old head may be a 2 that is now near the end. ReturnzeroHead.next. - No 0s at all:
zerois still the dummy, sozeroHead.nextbecomes the ones line (or the twos line). The code needs no special case.
What interviewers ask next
- Do it on an array (the Dutch national flag problem). Use three fingers
low,mid,highand swap in place: a 0 swaps tolow, a 2 swaps tohigh, a 1 just movesmidon. - Why not use the array trick on a list? It needs to swap with the back end, and a singly list cannot walk backwards. Three lines are the natural list version.
- What if values go from 0 to
m? Usem + 1lines (orm + 1counters). That is counting sort,O(n + m). - Make it one walk with counting? Counting needs two walks, because you must know the counts before writing. The three lines way is a single walk.
Remember this
Grown-up words: the bins are three sublists with dummy head nodes, counting and overwriting is counting sort, and the array version with three fingers is the Dutch national flag algorithm.