Lesson 16 of 250
75. Sort Colors
NeetCode: Sort Colors · LeetCode: 75. Sort Colors · Difficulty: Medium
Given an array nums with n objects colored red, white or blue (encoded as 0, 1, 2), sort them in place so that objects of the same color are adjacent, in the order red, white, blue. The intended solution does not use the library sort.
Example
Input: nums = [2, 0, 2, 1, 1, 0] Output: [0, 0, 1, 1, 2, 2]
Input: nums = [2, 0, 1] Output: [0, 1, 2]Brute force: general-purpose sort
Call the library sort. It is correct but does not exploit that there are only three distinct values. Java arrays have a fixed length, so the method sorts the int[] in place and returns nothing, as LeetCode's signature does.
import java.util.Arrays;
public class Main {
static class Solution {
public void sortColors(int[] nums) {
Arrays.sort(nums);
}
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] a = {2, 0, 2, 1, 1, 0};
sol.sortColors(a);
System.out.println(Arrays.toString(a));
int[] b = {2, 0, 1};
sol.sortColors(b);
System.out.println(Arrays.toString(b));
int[] c = {};
sol.sortColors(c);
System.out.println(Arrays.toString(c));
}
}[0, 0, 1, 1, 2, 2]
[0, 1, 2]
[]Time: O(n log n). Space: O(log n) for the recursion of the dual-pivot quicksort that Arrays.sort(int[]) uses.
Better: counting sort, two passes
Count how many zeros, ones and twos there are, then overwrite the array with that many of each. Only three counters are needed.
import java.util.Arrays;
public class Main {
static class Solution {
public void sortColors(int[] nums) {
int[] counts = new int[3];
for (int x : nums) {
counts[x]++;
}
int i = 0;
for (int color = 0; color < 3; color++) {
for (int k = 0; k < counts[color]; k++) {
nums[i++] = color;
}
}
}
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] a = {2, 0, 2, 1, 1, 0};
sol.sortColors(a);
System.out.println(Arrays.toString(a));
int[] b = {2, 0, 1};
sol.sortColors(b);
System.out.println(Arrays.toString(b));
int[] c = {};
sol.sortColors(c);
System.out.println(Arrays.toString(c));
}
}[0, 0, 1, 1, 2, 2]
[0, 1, 2]
[]Time: O(n) with two passes. Space: O(1).
Optimal: Dutch national flag, one pass
Maintain three regions with pointers low, mid, high: nums[0..low) are all 0, nums[low..mid) are all 1, nums[high+1..] are all 2, and nums[mid..high] (both ends included) is still unknown. Look at nums[mid]:
0: swap withnums[low], then advance bothlowandmid(the swapped-in value is a known 1).1: already in place, advancemid.2: swap withnums[high]and shrinkhigh; do not advancemidbecause the swapped-in value is unexamined.
high becomes -1 for an empty array or when every element is a 2, which is fine because int can be negative and the loop condition mid <= high then fails.
import java.util.Arrays;
public class Main {
static class Solution {
public void sortColors(int[] nums) {
int low = 0;
int mid = 0;
int high = nums.length - 1; // nums[high + 1..] are all 2s
while (mid <= high) {
if (nums[mid] == 0) {
swap(nums, low, mid);
low++;
mid++;
} else if (nums[mid] == 1) {
mid++;
} else {
swap(nums, mid, high);
high--;
}
}
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] a = {2, 0, 2, 1, 1, 0};
sol.sortColors(a);
System.out.println(Arrays.toString(a));
int[] b = {2, 0, 1};
sol.sortColors(b);
System.out.println(Arrays.toString(b));
int[] c = {};
sol.sortColors(c);
System.out.println(Arrays.toString(c));
}
}[0, 0, 1, 1, 2, 2]
[0, 1, 2]
[]Time: O(n), each step either advances mid or shrinks the unknown region. Space: O(1).
