Given an array of_n_objects with_k_different colors (numbered from 1 to k), sort them so that objects of the same color are adjacent, with the colors in the order 1, 2, ... k.
Notice
You are not suppose to use the library's sort function for this problem.
Example
Given colors=[3, 2, 2, 1, 4],k=4, your code should sort colors in-place to[1, 2, 2, 3, 4].
A rather straight forward solution is a two-pass algorithm using counting sort. That will cost O(k) extra memory. Can you do it without using extra memory?
老师提过什么rainbow sort,这里只写了counting sort和3 way partition。
public void sortColors2(int[] colors, int k) {
if (colors == null || colors.length == 0) {
return;
}
sortHelper(colors, 0, colors.length - 1, 1, k);
}
private void sortHelper(int[] colors, int start, int end,
int colorStart, int colorEnd) {
if (colorStart == colorEnd) {
return;
}
if (start == end) {
return;
}
int midColor = (colorStart + colorEnd) / 2;
int left = start;
int right = end;
while (left <= right) {
while (left <= right && colors[left] <= midColor) { // <=,不然会stack overflow
left++;
}
while (left <= right && colors[right] > midColor) {
right--;
}
if (left <= right) {
int tmp = colors[left];
colors[left] = colors[right];
colors[right] = tmp;
left++;
right--;
}
}
sortHelper(colors, start, right, colorStart, midColor);
sortHelper(colors, left, end, midColor + 1, colorEnd); // +1,不然会stack overflow
}
counting sort:
public void sortColors2(int[] colors, int k) {
if (colors == null || colors.length == 0 || k < 1) {
return;
}
//counting sort version
int[] counts = new int[k];
for (int i = 0; i < colors.length; i++) {
counts[colors[i] - 1]++;
}
int i = 0;
int j = 0;
// counting sort, pay attention to bounds and indexs when putting numbers back
while (i < colors.length && j < counts.length) {
while (j < counts.length && counts[j] != 0) {
colors[i++] = j + 1;
counts[j]--;
}
j++;
}
}
public void sortColors2(int[] colors, int k) {
if (colors == null || colors.length == 0 || k < 1) {
return;
}
threeWayPartition(colors, 0, colors.length - 1);
}
private void threeWayPartition(int[] A, int start, int end) {
if (start >= end || start < 0 || end >= A.length) {
return;
}
int mid = start + (end - start) / 2;
int pivot = A[mid];
int i = start;
int left = i;
int right = end;
while (i <= right) {
if (A[i] == pivot) {
i++;
} else if (A[i] < pivot) {
swap(A, i, left);
i++;
left++;
} else {
swap(A, i, right);
right--;
}
}
threeWayPartition(A, start, left);
threeWayPartition(A, i, end);
}
private void swap(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}