Brute force sort → counting sort → Dutch National Flag one-pass algorithm. Three pointers, zero extra space.
Problem Statement
An array nums with n objects coloured red, white, or blue, represented by integers 0, 1, and 2 respectively. Sort them in-place so that objects of the same colour are adjacent, in the order 0 → 1 → 2. You cannot use a library sort function.
Example 1
Input: [2, 0, 2, 1, 1, 0]
Output: [0, 0, 1, 1, 2, 2]
Example 2
Input: [2, 0, 1]
Output: [0, 1, 2]
Follow-up: Can you solve it in one pass using only constant extra space?
Why Is It Called the Dutch National Flag? 🇳🇱
This problem was formulated by computer scientist Edsger W. Dijkstra. The Dutch national flag has three horizontal bands — red, white, and blue — exactly like our three values 0, 1, 2. Dijkstra’s challenge: partition any sequence of red, white, and blue elements into those three groups in a single pass.
Goal: transform any ordering into this:
Three Approaches — Building up to Optimal
🐌 Approach 1
Built-in Sort
Call the language’s sort. Works, but O(n log n) and violates the spirit of the problem.
📊 Approach 2
Counting Sort
Count 0s, 1s, 2s in one pass. Overwrite the array in a second pass. Two passes, O(n).
⚡ Approach 3
Dutch National Flag
Three pointers, one pass, in-place. Constant space. The interview answer.
Approach 1 — Built-in Sort
The naive idea: just sort the array. Since values are 0, 1, 2 any comparison sort works. This violates the follow-up constraint and misses the educational point entirely, but it’s worth mentioning as a baseline.
Approach 2 — Counting Sort (Two Pass)
Since there are only three distinct values, we can count each one, then overwrite the array. Simple, but requires two passes over the data.
- Pass 1: iterate through
numsand count how many 0s, 1s, and 2s exist. - Pass 2: overwrite
nums— writecount0zeros, thencount1ones, thencount2twos. - Return. (No extra data structure needed beyond three counters.)
🔍 Dry Run — Counting Sort
Input: [2, 0, 2, 1, 1, 0]
| Pass | Action | State |
|---|---|---|
| Pass 1 | Count values | count0=2, count1=2, count2=2 |
| Pass 2a | Write 2 zeros | [0, 0, _, _, _, _] |
| Pass 2b | Write 2 ones | [0, 0, 1, 1, _, _] |
| Pass 2c | Write 2 twos | [0, 0, 1, 1, 2, 2] ✅ |
Approach 3 — Dutch National Flag (Optimal) ⚡
The Three-Pointer Idea
We maintain three pointers that divide the array into four live regions at all times:
0..left−1
All confirmed 0s (reds)
left..mid−1
All confirmed 1s (whites)
mid..right
Unknown — not yet classified
right+1..n−1
All confirmed 2s (blues)
We always inspect nums[mid] (the first unknown element) and take one of three actions:
| nums[mid] value | Action | Why |
|---|---|---|
| 0 (red) | swap(mid, left) • left++ • mid++ | Belongs in red zone. After swap, left points at a 1 we’ve already seen, so mid can safely advance. |
| 1 (white) | mid++ | Already in the right zone. Just expand white region rightward. |
| 2 (blue) | swap(mid, right) • right-- | Belongs in blue zone. After swap, the new nums[mid] is unknown — do NOT advance mid. |
❓ Why doesn’t mid advance when we swap a 2?
When we swap nums[mid] with nums[right], the value that comes to mid from the right side has never been examined before — it could be 0, 1, or 2. We must inspect it before moving on. When we swap a 0 with nums[left], the value at left must be a 1 (we’ve already classified everything before mid), so we can safely advance both pointers.
🔍 Dry Run — Dutch National Flag
Input: [2, 0, 2, 1, 1, 0]
Initial: left=0, mid=0, right=5
Time & Space Complexity
| Approach | Time | Space | Passes | Note |
|---|---|---|---|---|
| Built-in Sort | O(n log n) | O(1) | 1 | Violates problem spirit |
| Counting Sort | O(n) | O(1) | 2 | Simple but two sweeps |
| Dutch National Flag | O(n) | O(1) | 1 | Interview gold standard |
while (mid ≤ right) loop processes each element exactly once. When we encounter a 2 and swap, we don’t advance mid because we’ve never seen the incoming value. When we encounter a 0 and swap, the incoming value at left must already be a 1 (everything left of mid is classified), so advancing both is safe. This asymmetry is the core of the algorithm.