Browse curriculum

Sort Colors

Sort an array of 0s, 1s and 2s (red, white and blue) in place and in one pass, so equal colours sit together in the order red, white, blue.

Problem Understanding

The Goal

We need to sort an array containing only 0s, 1s, and 2s. The catch is that we must do this in-place (without creating a new array) and ideally in one pass (O(n) time).

  • 0: Represents Red (should be at the beginning)
  • 1: Represents White (should be in the middle)
  • 2: Represents Blue (should be at the end)

Input/Output Examples

  • Input: nums = [2, 0, 2, 1, 1, 0]

  • Output: [0, 0, 1, 1, 2, 2]

  • Input: nums = [2, 0, 1]

  • Output: [0, 1, 2]

Constraints

  • n == nums.length
  • 1 <= n <= 300
  • nums[i] is either 0, 1, or 2.

Note: A simple solution would be to count the number of 0s, 1s, and 2s, and then overwrite the array. However, the "Dutch National Flag" algorithm allows us to do this in a single pass with constant space.

Algorithm Strategy

The Dutch National Flag Algorithm

This problem is a classic variation of the Dutch National Flag problem proposed by Edsger Dijkstra. We use three pointers to partition the array into three sections:

  1. low: The boundary for 0s (Red). Everything before low is 0.
  2. high: The boundary for 2s (Blue). Everything after high is 2.
  3. mid: The current element iterator. Everything between low and mid is 1 (White).

The Logic

We iterate with the mid pointer and check nums[mid]:

  1. If nums[mid] == 0:
    • This belongs in the "0 zone" (at the start).
    • Swap nums[mid] with nums[low].
    • Increment both low and mid.
  2. If nums[mid] == 1:
    • This belongs in the middle. It's already in the right relative place.
    • Just increment mid.
  3. If nums[mid] == 2:
    • This belongs in the "2 zone" (at the end).
    • Swap nums[mid] with nums[high].
    • Decrement high.
    • Crucial: Do NOT increment mid yet! The element we just swapped from high to mid hasn't been checked. We need to process it in the next iteration.

Visualizing the Zones

[0, 0, ... 0    1, 1, ... 1    ?, ?, ... ?    2, 2, ... 2]
^              ^              ^              ^
0             low            mid            high

Visualization

Watch low, mid and high partition the array: everything before low is 0, everything after high is 2, and mid decides where the next value goes.

Dry Run

Let's trace the algorithm with nums = [2, 0, 2, 1, 1, 0].

Iteration Array State low mid high Action
Start [2, 0, 2, 1, 1, 0] 0 0 5 Initial state
1 [2, 0, 2, 1, 1, 0] 0 0 5 nums[mid] is 2. Swap mid, high. high--
[0, 0, 2, 1, 1, 2] 0 0 4 (After swap)
2 [0, 0, 2, 1, 1, 2] 0 0 4 nums[mid] is 0. Swap mid, low. low++, mid++
[0, 0, 2, 1, 1, 2] 1 1 4 (After swap)
3 [0, 0, 2, 1, 1, 2] 1 1 4 nums[mid] is 0. Swap mid, low. low++, mid++
[0, 0, 2, 1, 1, 2] 2 2 4 (After swap)
4 [0, 0, 2, 1, 1, 2] 2 2 4 nums[mid] is 2. Swap mid, high. high--
[0, 0, 1, 1, 2, 2] 2 2 3 (After swap)
5 [0, 0, 1, 1, 2, 2] 2 2 3 nums[mid] is 1. mid++
6 [0, 0, 1, 1, 2, 2] 2 3 3 nums[mid] is 1. mid++
End [0, 0, 1, 1, 2, 2] 2 4 3 mid > high, loop ends.

Edge Cases & Common Mistakes

Common Pitfalls

  1. Incrementing mid after swapping with high: This is the most common bug. When you swap with high, the new element at mid could be a 0 or a 2. You must check it again.
  2. Off-by-one errors: Ensure logic handles the last element properly (use mid <= high).

Edge Cases

  • No 0s, 1s, or 2s: E.g., [1, 1, 1] or [2, 2, 2]. The algorithm still works.
  • Already Sorted: The pointers will just verify the order.
  • Reverse Sorted: [2, 2, 1, 1, 0, 0]. Just requires more swaps.

Code Solutions

Implementations in JavaScript, TypeScript, Python, Java, C and C++.

Sort Colors Code
1function sortColors(nums) {
2 let low = 0;
3 let mid = 0;
4 let high = nums.length - 1;
5
6 while (mid <= high) {
7 if (nums[mid] === 0) {
8 [nums[low], nums[mid]] = [nums[mid], nums[low]];
9 low++;
10 mid++;
11 } else if (nums[mid] === 1) {
12 mid++;
13 } else {
14 [nums[mid], nums[high]] = [nums[high], nums[mid]];
15 high--;
16 // mid is NOT incremented yet
17 }
18 }
19};

The approach, step by step

  1. Set three pointers

    low = 0, mid = 0, high = n - 1.

  2. Look at nums[mid]

    While mid ≤ high, check the value at mid.

  3. Place it

    A 0 swaps with low and both move on; a 1 moves mid on; a 2 swaps with high and only high moves.

Frequently asked questions

What is the Dutch National Flag algorithm?

A one-pass, in-place partition into three groups. Everything before low is 0, everything after high is 2, and mid scans the unknown region between them, swapping each value into its group.


Why does mid not move after swapping with high?

The value swapped in from high has not been examined yet — it could be a 0, 1 or 2 — so mid stays and checks it on the next step. A value swapped in from low is always a 1 or already checked, so mid can move on then.


What is the time and space complexity of Sort Colors?

O(n) time, because every step either advances mid or shrinks high, and O(1) extra space.

Applying for software engineering roles? Free, no sign-up:

AI resume checker — match your resume to the job description