Algorithm

Sort Colors (Dutch National Flag)

Two Pointer Pattern

Sort Colors (Dutch National Flag)

Given an array nums holding only the values 0, 1, and 2 (standing for the colors red, white, and blue), sort it in place so all the 0s come first, then all the 1s, then all the 2s. Do not call a library sort. The array is rearranged directly — the function returns nothing. The ideal solution makes a single pass using O(1) extra space.

CONSTRAINTS
  • n == nums.length
  • 1 <= n <= 300
  • nums[i] is 0, 1, or 2
  • Target: one pass, O(1) extra space, no library sort
EXAMPLE 1
Input: nums = [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]
All 0s come first, then the 1s, then the 2s.
EXAMPLE 2
Input: nums = [2,0,1]
Output: [0,1,2]
One of each, arranged into the required 0-then-1-then-2 order.
EXAMPLE 3
Input: nums = [1,1,1]
Output: [1,1,1]
All values are the same, so nothing needs to move.
Can the input contain values other than 0, 1, and 2?
No — only those three. That is exactly what lets us skip a general sort.
Is a two-pass counting solution acceptable?
It is correct and O(N), but the intended answer is a single pass with O(1) extra space.
Does the array get sorted in place, or should I return a new one?
In place. The original array is rearranged and nothing is returned.

We have an array made of just three values — 0, 1, and 2 — and we want them grouped in order: every 0, then every 1, then every 2. A general sorting algorithm would work but costs O(N log N) and ignores how little variety there is. With only three possible values we can do much better.

The easy baseline: count, then rewrite

The simplest fast idea is to make two passes. First pass: count how many 0s, 1s, and 2s there are. Second pass: overwrite the array with that many 0s, then that many 1s, then the 2s. This is O(N) time and O(1) space, and honestly it is fine. The only thing left to improve is that it touches the array twice — can we finish it in a single sweep?

python
counts = [0, 0, 0]
for x in nums:
    counts[x] += 1
i = 0
for color in range(3):
    for _ in range(counts[color]):
        nums[i] = color
        i += 1
One pass with three regions growing toward each other

In Move Zeroes we used a single write pointer to split an array into two parts — keepers packed in front, the rest behind. Here we have three groups instead of two, so we grow two finished regions inward from the ends and sweep the unknown middle. Three markers do it:
- low — everything before low is a settled 0.
- high — everything after high is a settled 2.
- mid — the scanner, checking one value at a time, starting at the front.

Everything between low and mid is known to be 1, and everything from mid to high is still unexamined. As mid walks, it sorts each value into its region:
- Sees a 0: it belongs at the front, so swap it down to low, then move both low and mid forward.
- Sees a 2: it belongs at the back, so swap it up to high, then move high inward — but leave mid where it is.
- Sees a 1: it is already in the middle where 1s live, so just step mid forward.

python
low, mid = 0, 0
high = len(nums) - 1
while mid <= high:
    if nums[mid] == 0:
        nums[low], nums[mid] = nums[mid], nums[low]
        low += 1
        mid += 1
    elif nums[mid] == 2:
        nums[mid], nums[high] = nums[high], nums[mid]
        high -= 1                        # note: mid does NOT advance here
    else:                                # nums[mid] == 1
        mid += 1
Crucial Notethe one subtlety is why mid moves after a 0-swap but not after a 2-swap. When we swap a 0 down to low, the value that comes back to mid came from the region behind mid — which we already know holds only 1s — so it is safe and mid can move on. But when we swap a 2 up to high, the value that comes back to mid came from the unexamined region near high. We have not looked at it yet, so mid must stay and inspect it next. Advancing mid there is the classic bug — it can skip a 0 and leave it stranded in the wrong place.
Worked example:nums = [2, 0, 2, 1, 1, 0]
- low=0, mid=0, high=5. mid sees 2 → swap with high: [0, 0, 2, 1, 1, 2], high=4. mid stays to inspect the new value.
- mid sees 0 → swap with low (no visible change): low=1, mid=1.
- mid sees 0 → swap with low: low=2, mid=2.
- mid sees 2 → swap with high: [0, 0, 1, 1, 2, 2], high=3. mid stays.
- mid sees 1 → mid=3. mid sees 1 → mid=4. Now mid > high, stop.
- Result: [0, 0, 1, 1, 2, 2].
The specialty, and when to reach for it

This three-pointer sweep is called the Dutch National Flag partition, and its real lesson generalizes past colors: when you must rearrange an array in place into a small, fixed number of categories in one pass, grow the finished categories inward from the boundaries and scan the shrinking unknown middle. Move Zeroes was the two-category version (keep vs. not) with one boundary pointer; this is the three-category version with two. The signal to reach for it: the values come from a tiny fixed set (or split cleanly into "less than / equal / greater than a pivot" — which is exactly how quicksort partitions), and you want O(1) space and a single sweep. The invariant that keeps it correct — before low all 0s, before mid all 1s, after high all 2s — is the thing to hold in your head; every move preserves it.

Interactive Strategy Visualization

Dutch National Flag

3-Way Partitioning with Pointers

LOW
MID
2
0
0
1
2
2
1
3
1
4
HIGH
0
5
Initializing pointers: low and mid at 0, high at the end.
O(N log N) Comparison Sort
O(N) Time · O(1) Space Two-Pass Count
O(N) Time · O(1) Space One-Pass Partition