Beginner~9 min

Sort Colors

How to group an array of only three distinct values — 0, 1, and 2 — in a single pass, with no extra array and no counting step first.

The job

You have an array where every value is 0, 1, or 2. Rearrange it so every 0 comes first, then every 1, then every 2 — in one pass, in place.

The obvious way

Count how many 0s, 1s, and 2s there are, then overwrite the array with that many of each in order — two passes, and it needed to know the full counts first.Two full passes over the array, plus a small counting array.

The idea

Keep three positions: `low` and `high` mark the boundaries of the 0-group and 2-group, growing inward as values are confirmed. `mid` scans between them — a 0 gets swapped down to `low`, a 2 gets swapped up to `high`, and a 1 is already exactly where it belongs, so `mid` just steps past it.

Think of it like this. Sorting a laundry basket of red, white, and blue socks by tossing each one straight into its own pile as you touch it — reds pile up on the left, blues on the right, whites stay in the middle — instead of sorting the whole pile by counting colors first.

Three regions, one scan

low
mid
high
Resolved
/ 6

6 values, each 0, 1, or 2. Group them in one pass: all the 0s first, then the 1s, then the 2s.

0.0s/ 13.1s
sort_colors.pypython
def sort_colors(nums):
    low, mid, high = 0, 0, 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] == 1:
            mid += 1
        else:
            nums[mid], nums[high] = nums[high], nums[mid]
            high -= 1

This run

Every value is grouped: 0s first, then 1s, then 2s — sorted in one left-to-right pass over 6 positions, no extra array.

Try:

The names you just watched

low, mid, high

`low` and `high` mark confirmed boundaries and only ever move inward. `mid` is the only pointer that actually reads values, and it always sits between the other two.

Why mid doesn't always advance

Swapping with `low` brings a value already known to be 0 or 1 into `mid`'s slot, so it is safe to step past. Swapping with `high` brings an UNKNOWN value in — it must be checked again.

One pass, not two

Because every value is classified and placed the moment `mid` reaches it, there is no separate counting pass and no second write-through of the array.

How to spot this shape

The tell: You need to partition an array into three known, ordered groups in place, and a brute-force answer would count each group first and rebuild the array from those counts.

Reach for it when

  • The values fall into a small, fixed number of categories (here, exactly three).
  • The target order of the categories is known in advance.
  • The task explicitly forbids extra space or a full sort.
  • A two-region version of the same idea (see Move Zeroes) is the natural warm-up.

Not this when

  • The categories are not known in advance, or there are many of them — that wants counting sort or a hash map instead.
  • A full comparison sort is acceptable — this technique only pays off because the domain is tiny.
  • The elements are not randomly accessible (e.g. a linked list) — the swap-based walk does not translate directly.

Practice

6 problems
LeetCodeO(n) / O(1)

The lesson, exactly. Three regions, one scanning pointer, at most one pass.

LeetCodeO(n) / O(1)

The two-region version of this exact idea — one write pointer instead of two.

LeetCodeO(n) average / O(1)

Quickselect uses the same three-way partition around a pivot — just with an arbitrary pivot value instead of a fixed 0/1/2.

LeetCodeO(n) / O(1)

Find the median, then three-way partition around it with a virtual index mapping — the same low/mid/high shape in disguise.

LeetCodeO(n) / O(1)

A two-region partition (even vs. odd) — the low/high half of this lesson without the middle group.

LeetCodeO(n) / O(1)

Two SEPARATE scanning pointers (one over even slots, one over odd slots) instead of one shared mid — a variation worth comparing against this lesson’s single-scanner shape.