问题
思路
以下思路参考[算法系列之十一荷兰国旗问题]
我们可以把数组分成三部分,前部(全部是0),中部(全部是1)和后部(全部是2)三个部分,每一个元素(红白蓝分别对应0、1、2)必属于其中之一。
将前部和后部各排在数组的前边和后边,中部自然就排好了。
设置两个指针begin指向前部的末尾的下一个元素(刚开始默认前部无0,所以指向第一个位置),end指向后部开头的前一个位置(刚开始默认后部无2,所以指向最后一个位置),然后设置一个遍历指针current,从头开始进行遍历。
(1)若遍历到的位置为1,则说明它一定属于中部,根据总思路,中部的我们都不动,然后current向前移动一个位置。
(2)若遍历到的位置为0,则说明它一定属于前部,于是就和begin位置进行交换,然后current向前移动一个位置,begin也向前移动一个位置(表示前边的已经都排好了)。
(3)若遍历到的位置为2,则说明它一定属于后部,于是就和end位置进行交换,由于交换完毕后current指向的可能是属于前部的,若此时current前进则会导致该位置不能被交换到前部,所以此时current不前进。而同1),end向前移动一个位置。
这里面有几个点需要搞清楚:
1.begin end的意义
2.begin end怎么初始化
3.为什么与前部进行了交换,cur++?这是为什么?
可以这么考虑:
由于begin < end是肯定的,所以,如果交换之后,需要再次判断那只有一种可能就是这个元素是2,但是,都已经访问到cur,前面又怎么可能存在2。但是,后面的交换是可能的,所以需要再次判断。
代码
class Solution {
public:
void sortColors(vector<int>& nums) {
int begin = 0;
int end = nums.size() - 1;
int cur = 0;
while(cur <= end) {
if( nums[cur] == 1 ) ++cur;
else if( nums[cur] == 0 ) { swap( nums[begin], nums[cur] ); ++begin; ++cur; }
else { swap( nums[cur], nums[end] ); --end; }
}
}
private:
void swap(int& a, int& b) {
int t = a;
a = b;
b = t;
}
};