Home
DSA Patterns
Two Pointers
Sort Colors
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.length1 <= n <= 300nums[i]is either0,1, or2.
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:
low: The boundary for 0s (Red). Everything beforelowis0.high: The boundary for 2s (Blue). Everything afterhighis2.mid: The current element iterator. Everything betweenlowandmidis1(White).
The Logic
We iterate with the mid pointer and check nums[mid]:
- If
nums[mid] == 0:- This belongs in the "0 zone" (at the start).
- Swap
nums[mid]withnums[low]. - Increment both
lowandmid.
- If
nums[mid] == 1:- This belongs in the middle. It's already in the right relative place.
- Just increment
mid.
- If
nums[mid] == 2:- This belongs in the "2 zone" (at the end).
- Swap
nums[mid]withnums[high]. - Decrement
high. - Crucial: Do NOT increment
midyet! The element we just swapped fromhightomidhasn'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
- Incrementing
midafter swapping withhigh: This is the most common bug. When you swap withhigh, the new element atmidcould be a 0 or a 2. You must check it again. - 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;56 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 yet17 }18 }19};
