给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
示例:
输入: [2,0,2,1,1,0] 输出: [0,0,1,1,2,2]
先看这个题目,这个题目不仅仅是一个排序的问题,它的特点在于数组中的元素是固定的3个0,1,2,也就是说我们可以利用这个特性来优化一般性的排序
由于数组中只有0,1,2,因此最后排序完成后一定是0在前,2在后,1在中间。
如果我们使用三个指针left,right与cur。left一直指向0的后开区间,right指向2的前开区间,也就是说[0,left)间全为0,(right,nums.size()-1]间全为2。当cur为0时,交换left与cur的值,并将0区间的下限left右移;当cur=2时,交换right与cur的值,并将right左移。
现在唯一的问题在于循环这个过程中left,right,cur的加减问题。
现在假设cur已经领先于left:
首先对于left来说:
如果left为2,那么在之前cur遍历到这个2时已经将这个2交换到2区间了,也就是说left指向的值只可能是1(如果left指向的是0,则left应该在当前left的右边)。
其次对于right来说:
cur与right交换后,right原来的值可能是0,可能是1,也可能是2。
因此:
cur=0时,交换cur与left的值,并left++,且cur++; cur++的目的是因为left指的值一定是1,因此交换后cur当前为1,cur=1既不用向前交换也不用向后交换,因此cur在交换后要自增一次。
cur=2时,交换cur与right的值,并right--,但此时cur不能自加了。 这里cur不能自加是因为,right原来指向的值可能是0,1,2。假如是1,当然可以自加,但如果是0或2,则自加后跳过了这个值,等价于没有对这个交换前的right的值进行排序,因此不能cur++。
class Solution { public: void sortColors(vector<int>& nums) { if(nums.empty()) return; int l=0; int r=nums.size()-1; int cur=0; while(cur<=r&&l<nums.size()&&r>=0) { if(nums[cur]==0) { swap(nums[l],nums[cur]); l++; cur++; continue; } if(nums[cur]==2) { swap(nums[r],nums[cur]); r--; continue; } cur++; } } };