10 - (0-1-2) Sort
Problem¶
Sort an array containing only 0s, 1s, and 2s in a single pass without using any extra space (\(O(1)\) space).
Intuition¶
This problem is a classic application of the three-way partitioning algorithm proposed by Edsger Dijkstra. The idea is to maintain three sections in the array:
1. [0...low-1] containing all 0s.
2. [low...mid-1] containing all 1s.
3. [mid...high] containing unknown elements.
4. [high+1...n-1] containing all 2s.
By iterating through the array and swapping elements, we shrink the "unknown" section until the array is fully sorted.
Algorithm Steps¶
- Initialize three pointers:
low = 0,mid = 0,high = n - 1. - While
mid <= high: - Case A:
A[mid] == 0: SwapA[low]andA[mid]. Increment bothlowandmid. - Case B:
A[mid] == 1: Simply incrementmid. - Case C:
A[mid] == 2: SwapA[mid]andA[high]. Decrementhigh. (Do not incrementmidyet, as the swapped element needs to be checked).
Pseudocode¶
procedure sort012(A)
low := 0, mid := 0, high := n - 1
while mid <= high do
if A[mid] == 0 then
swap(A[low], A[mid])
low++, mid++
else if A[mid] == 1 then
mid++
else
swap(A[mid], A[high])
high--
end while
end procedure
Java Code using JCF¶
Using a competitive programming structure (TCS NQT Style).
import java.util.*;
public class Main {
/**
* Dutch National Flag Algorithm Implementation
*/
public static void sort012(List<Integer> list) {
int low = 0, mid = 0, high = list.size() - 1;
while (mid <= high) {
switch (list.get(mid)) {
case 0 -> {
Collections.swap(list, low, mid);
low++;
mid++;
}
case 1 -> mid++;
case 2 -> {
Collections.swap(list, mid, high);
high--;
}
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
if (sc.hasNextInt()) {
int t = sc.nextInt();
while (t-- > 0) {
if (sc.hasNextInt()) {
int n = sc.nextInt();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
if (sc.hasNextInt()) {
list.add(sc.nextInt());
}
}
sort012(list);
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + (i == list.size() - 1 ? "" : " "));
}
System.out.println();
}
}
}
sc.close();
}
}
Sample Input and Output¶
Input:
Output:
Complexity¶
| Case | Time Complexity | Space Complexity |
|---|---|---|
| All Cases | \(O(n)\) | \(O(1)\) |
- Single Pass: Performs exactly one pass over the array.
- In-place: No extra space used besides pointers.
- Stable: Generally No (swapping can change the relative order of equal 0s or 2s).
Example and Dry Run¶
Input: [2, 0, 2, 1, 1]
Pointers: low=0, mid=0, high=4
A[0] = 2: SwapA[0], A[4].high=3. Array:[1, 0, 2, 1, 2]A[0] = 1:mid=1. Array:[1, 0, 2, 1, 2]A[1] = 0: SwapA[0], A[1].low=1, mid=2. Array:[0, 1, 2, 1, 2]A[2] = 2: SwapA[2], A[3].high=2. Array:[0, 1, 1, 2, 2]-
A[2] = 1:mid=3. Loop ends (mid > high). -
Result:
[0, 1, 1, 2, 2]
Variations¶
- Sort 0-1 (Two Pointers): Simpler version where you only have two distinct elements.
- Move Negative Numbers to Front: Similar partitioning logic for positive/negative numbers.
- Partitioning around a Pivot: Used in Quick Sort (though Quick Sort usually partitions into 2 sections, 3-way partitioning is an optimization).