Linked List · 34 of 36
Segregate even and odd nodes in a Linked List
Move every even box of a chain to the front and every odd box to the back, keeping each group in its old order, by building two little lines and joining them.
- Simple way
- time O(n)
room O(n) - Clever way
- time O(n)
room O(1)
The problem, simply
You get a linked list of whole numbers. Rearrange it so that all boxes with even numbers come first and all boxes with odd numbers come after them.
Inside each group, keep the old order. If 8 came before 2 in the input, 8 must still come before 2. Give back the new head.
A story to remember it
Picture it
The chain 3 8 5 2 9 6 4. Even boxes and odd boxes are shown in two different colors.
- checking
- path
Examples
A normal case
- In
3 -> 8 -> 5 -> 2 -> 9 -> 6 -> 4- Out
8 -> 2 -> 6 -> 4 -> 3 -> 5 -> 9
Evens in their old order, then odds in their old order. The head changes from 3 to 8.
Classic case
- In
17 -> 15 -> 8 -> 12 -> 10 -> 5 -> 4 -> 1 -> 7 -> 6- Out
8 -> 12 -> 10 -> 4 -> 6 -> 17 -> 15 -> 5 -> 1 -> 7
Five evens, then five odds.
All odd
- In
1 -> 3 -> 5- Out
1 -> 3 -> 5
The even line stays empty, so the answer is the odd line, unchanged.
Already sorted the right way
- In
2 -> 4 -> 7- Out
2 -> 4 -> 7
Nothing moves.
Negative numbers and zero
- In
-3 -> 0 -> -4 -> 5- Out
0 -> -4 -> -3 -> 5
0 and -4 are even. -3 and 5 are odd.
Way 1: the simple way
Copy the numbers out, then write them back in the right order.
- Walk the chain. Put even numbers in one list and odd numbers in another.
- Walk the chain again and write all the even numbers into the boxes, then all the odd numbers.
The numbers are copied into two lists. Now they get written back over the boxes from the head: 8 2 6 4 3 5 9.
- checking
- path
import java.util.*;
class Solution {
public Node divide(Node head) {
List<Integer> evens = new ArrayList<>(), odds = new ArrayList<>();
for (Node cur = head; cur != null; cur = cur.next) {
if (cur.data % 2 == 0) evens.add(cur.data);
else odds.add(cur.data);
}
Node cur = head;
for (int x : evens) { cur.data = x; cur = cur.next; } // evens first
for (int x : odds) { cur.data = x; cur = cur.next; } // then odds
return head;
}
}How long it takes: two walks, O(n). Extra room: the two lists hold every number, O(n). It also copies numbers instead of moving boxes, which many interviewers do not accept.
Way 2: the clever way
Do what the teacher did. Build two lines out of the real boxes, then join them.
- Make two dummy boxes, one for the even line and one for the odd line. Each line has a tail finger.
- Walk the chain. Hook each box to the end of its line and move that line's tail.
- Hook the end of the even line to the first box of the odd line.
- Set the odd tail's
nexttonull, because it may still point to an old neighbor. - Give back the box after the even dummy.
Two lines, then one
01 / 10
Two empty lines are waiting, each with a dummy box in front (not drawn). curr is on 3.
- looking now
- answer
- just added
class Solution {
public Node divide(Node head) {
Node evenDummy = new Node(0), oddDummy = new Node(0);
Node evenTail = evenDummy, oddTail = oddDummy;
for (Node cur = head; cur != null; cur = cur.next) {
if (cur.data % 2 == 0) { evenTail.next = cur; evenTail = cur; }
else { oddTail.next = cur; oddTail = cur; }
}
evenTail.next = oddDummy.next; // evens, then odds
oddTail.next = null; // cut the old arrow at the end
return evenDummy.next; // works even when there are no evens
}
}How long it takes: one walk, O(n). Extra room: two dummy boxes and two tails, O(1). Boxes are moved, not copied, and the order inside each group is kept, so this split is stable.
Watch out for
- Testing odd with
x % 2 == 1fails for negative numbers in Java, because-3 % 2is-1. Test even withx % 2 == 0instead. - No even boxes at all:
evenTailis still the dummy, soevenDummy.next = oddDummy.nextand the answer is the odd line. The code handles it without a special case. - Return
evenDummy.next, nothead. The head changes whenever the first box is odd.
What interviewers ask next
- Group by position instead of value (LeetCode 328, odd even linked list): boxes 1, 3, 5 first, then 2, 4, 6. Use two fingers that jump two boxes each:
odd.next = even.next,even.next = odd.next, then join. - Odds first, then evens? Swap which line is joined to which.
- Split by a value
xinstead of parity (LeetCode 86, partition list): boxes smaller thanxfirst, others after. Same two lines. - Three groups, like 0s, 1s and 2s? Three lines, joined in order. That is the "sort a list of 0s, 1s and 2s" problem.
Remember this
Grown-up words: the boxes are nodes, the two lines are two sublists built with dummy head nodes, the tails are tail pointers, and keeping the old order inside each group makes this a stable partition.