Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
[分析] 此题就是排序至多有三种值的数组。自己的思路是通过遍历数组两次排序,第一次遍历将 0 全部放置在最前面一段,第二次遍历数组剩余元素将 1 放置在前面。 但这样做总觉得缺了什么,一定有只要遍历一次的做法。搜了下,果然。
http://blog.csdn.net/zxzxy1988/article/details/8596144 即使遍历两次还有另一种非常朴素的做法,第一次遍历计数0,1,2 的出现个数,第二次遍历就是根据计数赋值数组。
仅遍历一次的思路参考博文中分析得非常到位,尤其是三指针含义的解释以及更新规则。low指示1元素的开始,是0和1的分界线,high指示1元素的结尾,是1和2的分界线,因为low指向的元素是1,所以每次和mid交换后low 和 mid均要递增,而high指针指向的元素可能是0可能是1,换句话说,[mid, high]之间是尚未遍历的区域, 因此high 和mid交换后mid不能递增。
public class Solution {
// Method 2: scan only 1 time
public void sortColors(int[] nums) {
if (nums == null || nums.length == 0)
return;
int low = 0, mid = 0, high = nums.length - 1;
while (mid <= high) {
switch (nums[mid]) {
case 0:
swap(nums, low++, mid++); break;
case 1:
mid++; break;
case 2:
swap(nums, high--, mid); break;
default:
break;
}
}
}
// Method 1: scan 2 times
public void sortColors1(int[] nums) {
if (nums == null || nums.length == 0)
return;
int N = nums.length;
int i = reorder(nums, 0, 0);
if (i == N) return;
reorder(nums, i, 1);
}
private int reorder(int[] nums, int i, int t) {
int N = nums.length;
while (i < N && nums[i] == t) {
i++;
}
int j = i;
while (true) {
// find next 0
while (j < N && nums[j] > t) {
j++;
}
if (j == N) break;
swap(nums, i, j);
i++;
}
return i;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}