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; } }