Sort 0s, 1s and 2s (also known as Sort Colors or the Dutch National Flag problem) asks you to sort an array containing only three distinct values — in place, in a single pass. It is a classic test of the three-pointer partition trick.
Problem. Given an array a whose elements are only 0, 1, or 2, sort it in place so all
the 0s come first, then all the 1s, then all the 2s. Do it in one pass using O(1) extra space —
no counting and no library sort.
Example: a = [0, 2, 1, 2, 0, 1] → [0, 0, 1, 1, 2, 2].
The slow way first
The easy answer is counting sort: count how many 0s, 1s, and 2s there are, then overwrite the array with that many of each. It is O(n) time and O(1) space — but it takes two passes (one to count, one to write).
A general comparison sort like a.sort() is even worse: O(n log n), and it ignores the gift we were handed. We only have three possible values, so we should be able to place every element correctly in a single sweep.
The idea: partition into three regions
Keep three pointers that carve the array into four zones:
- everything left of
lowis a settled0, - everything right of
highis a settled2, - the band between
midandhighis unknown, - and
midis the cursor scanning that unknown band.
For each value at mid, do one of three things and the regions grow until the unknown band disappears:
The subtle part: when you swap a 2 down to high, mid does not advance — the value that came back from high is still unknown, so you must look at it again.
Walk through it
Step through the animation. Watch low build the wall of 0s from the left and high build the wall of 2s from the right while mid sweeps the middle. Settled boxes turn green. The loop ends the instant mid passes high — there is nothing unknown left to examine.
Pseudocode
low, mid = 0, 0
high = last index
while mid <= high:
if a[mid] == 0:
swap a[low] and a[mid] # send the 0 left
low += 1; mid += 1
else if a[mid] == 1:
mid += 1 # 1 is already in the middle
else: # a[mid] == 2
swap a[mid] and a[high] # send the 2 right
high -= 1 # do NOT move midThe Python solution
def sort_colors(a):
low, mid, high = 0, 0, len(a) - 1
while mid <= high:
if a[mid] == 0:
a[low], a[mid] = a[mid], a[low]
low += 1
mid += 1
elif a[mid] == 1:
mid += 1
else:
a[mid], a[high] = a[high], a[mid]
high -= 1
return alow,mid,highstart the unknown band as the whole array.- The loop runs while
mid <= high— once they cross, the unknown band is empty. a[mid] == 0: swap it down to thelowwall, then advance bothlowandmid(the value that came up tomidwas already scanned, so it is safe to step over).a[mid] == 1: it already belongs in the middle band, so onlymidmoves.a[mid] == 2: swap it up to thehighwall and shrinkhigh.midstays put because the swapped-in value is unexamined.
Complexity
| Case | Time | Notes |
|---|---|---|
| Library sort | O(n log n) (moderate) | ignores the 3-value structure |
| Counting sort | O(n) (moderate) | correct but two passes |
| Dutch National Flag | O(n) (moderate) | one pass, in place |
O(1) (fast)Each step moves either mid forward or high backward, and they only ever close toward each other, so the loop runs at most n times. No extra arrays — the sort happens inside the input.
When this pattern shows up
When a problem has a small, fixed number of categories and asks you to group them in place, think three-way partition. The same low/mid/high carving powers 3-way quicksort (the partition step that handles duplicate pivots) and any "segregate into buckets" question.
The one bug everyone writes: advancing mid after a 2-swap. You must not move mid there — the
element that just arrived from high has never been looked at and could itself be a 0 or 2.
Practice
For a = [0, 2, 1, 2, 0, 1] with low = mid = 0, the first value a[mid] is 0. What happens to low and mid?
1. Why does mid NOT advance after swapping a 2 to the high end?
2. When a[mid] is 0, which pointers advance?
3. What is the extra space used by the Dutch National Flag sort?
4. When does the while loop stop?