

基本思路:
用两个指针分别指向头部和尾部,一个动指针实现遍历,如果动指针发现0,就换到前面去,如果发现2就换到后面去。
自己最开始写得代码(没有通过):
class Solution {
public:
void sortColors(vector<int>& nums) {
int right = nums.size() -1;
int left = 0;
for(int med = 0; med < = right ; ){
if(nums[med] == 0){
swap(nums[med] , nums[left]);
left++;
}
if(nums[med] == 2){
swap(nums[med] , nums[right]);
right--;
}
if(nums[med] == 1){
med++;
}
}
}
};
自己写得代码前前后后改了好几次才通过,问题出现在:动指针什么时候往前走。
看到比较好的解答:
class Solution {
public:
void sortColors(vector<int>& nums) {
int left = 0;
int right = nums.size()-1;
for(int i = 0 ; i<= right ;i++){
if(nums[i]== 0 ){
swap(nums[i] , nums[left]);
left++;
}
if(nums[i]== 2 ){
swap(nums[i] , nums[right]);
right--;
if(nums[i] != 1){
i--;
}
}
}
}
};
看这里,作者对什么时候动指针往前走处理的很合适,动指针该不该往前走, 在于: 完成交换后,动指针当前位置是否换过来的是一个正确的值。就比如,交换之后如果是下图状态,i如果不管不顾,执行 i++,那肯定是不对的。因为显然这个“0”不在合适的位置上。

那能不能这样写判断语句:
class Solution {
public:
void sortColors(vector<int>& nums) {
int left = 0;
int right = nums.size()-1;
for(int i = 0 ; i<= right ;i++){
if(nums[i]== 0 ){
swap(nums[i] , nums[left]);
left++;
}
if(nums[i]== 2 ){
swap(nums[i] , nums[right]);
right--;
}
if(nums[i] != 1){ //单独写出来,交换位置之后,如果这个位置不是“1”,我就不往前走
i--;
}
}
}
};
答案是:不行!!!
如果其实数字是这样的,i的位置是0,i就必须往前走。

仔细思考一下,为什么只在right这边需要判断 i当前的值呢?
i是从左往右走的,i可以保证走过之后留下 0和1,且left指向的是“0”的结尾。但是right这边完全是混乱的,它和 i 交换之后有可能会把 i扰乱,所以要特别判断一下。
即:正着走就是一个普通的双指针,不用附加判断条件。
快排牛皮:
class Solution {
public:
static void sortColors(vector<int>& nums) {
int head = -1;
int tail = nums.size();
for (int i = 0; i < tail;) {
if (nums[i] == 1) {
i++;
}else if(nums[i] == 0) {
swap(nums[++head], nums[i++]);
}else if(nums[i] == 2) {
swap(nums[i], nums[--tail]);
}
}
}
};
作者:朱道斌
链接:https://leetcode-cn.com/leetbook/read/all-about-array/x9dam3/?discussion=MYvyU8
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
本文详细解析了三色旗问题的解决方案,通过双指针法实现了数组中0、1、2三类元素的快速排序。重点介绍了动指针移动时机的选择,并对比了不同实现方式的优劣。
2492

被折叠的 条评论
为什么被折叠?



