The problem requires us to sort an array containing only three distinct values: 0 (red), 1 (white), and 2 (blue). We must do this in-place without using the library’s sort function.
Why the Dutch National Flag Algorithm? This is a famous algorithm designed by Edsger Dijkstra specifically for this problem. The array is conceptually divided into four regions:
[0, low - 1]: strictly 0s.[low, mid - 1]: strictly 1s.[mid, high]: unknown, yet to be explored.[high + 1, n - 1]: strictly 2s.
By maintaining three pointers (low, mid, high), we evaluate the mid pointer. If we see a 0, we swap it to the low region. If we see a 2, we swap it to the high region. If we see a 1, we just leave it and move mid forward. This partitions the array in a single pass.
Specific questions to practice:
- Wiggle Sort
- Move Zeroes
- Partition Array According to Given Pivot
A simple two-pass approach. Pseudocode logic:
- First pass: Count the occurrences of 0s, 1s, and 2s using three variables or a hash map.
- Second pass: Overwrite the array. Fill the first
count(0)slots with 0, the nextcount(1)slots with 1, and the remaining with 2. Complexity: time, but requires two passes. The problem asks if we can do it in a single pass.
Pseudocode logic:
- Initialize
low = 0,mid = 0,high = nums.size() - 1. - While
mid <= high(while there are still unexplored elements):- If
nums[mid] == 0:- Swap
nums[low]andnums[mid]. - Increment both
lowandmid(we know the swapped-in value is a 1, somidis safe to advance).
- Swap
- If
nums[mid] == 1:- Just increment
mid.
- Just increment
- If
nums[mid] == 2:- Swap
nums[mid]andnums[high]. - Decrement
high. (Do not incrementmidhere, because the element swapped fromhighis unknown and needs to be evaluated next).
- Swap
- If
class Solution {
public:
void sortColors(std::vector<int>& nums) {
int low = 0;
int mid = 0;
int high = nums.size() - 1;
while (mid <= high) {
if (nums[mid] == 0) {
// 0 belongs to the low region
std::swap(nums[low], nums[mid]);
low++;
mid++;
} else if (nums[mid] == 1) {
// 1 belongs in the middle region, just move forward
mid++;
} else { // nums[mid] == 2
// 2 belongs to the high region
std::swap(nums[mid], nums[high]);
high--;
// Notice we do NOT increment mid here. The element we just
// swapped from 'high' needs to be checked on the next iteration.
}
}
}
};- Time Complexity:
- We traverse the array exactly once. The
midpointer moves forward, or thehighpointer moves backward, guaranteeing that the distance betweenmidandhighdecreases by 1 each step.
- We traverse the array exactly once. The
- Space Complexity:
- Only three pointers are used. The array is modified in-place.
- All elements are the same color: (e.g.,
[1, 1, 1]).midjust marches to the end.[0, 0, 0]: swapped with itself,lowandmidmarch.[2, 2, 2]:highdecreases until it crossesmid. - Array already sorted:
[0, 1, 2]. Handles smoothly. - Only two colors:
[0, 2].midstops immediately after crossinghigh.
- Recognition: Sorting an array containing only distinct values (where is very small, like 2 or 3) heavily hints at pointer-based partitioning logic instead of traditional comparison sorts like Merge Sort or Quick Sort.
- Mental Model: Think of
midas the “current explorer” moving left to right.lowis the “garbage bin for 0s” growing from the left.highis the “garbage bin for 2s” growing from the right.midgrabs an item, tosses it into the appropriate bin, and moves on. The trap is tossing a 2 into the right bin—you don’t know what item the right bin threw back at you, somidmust stay put and inspect the new item.