文章目录
一、题目
略,请见力扣 75 题。
二、题解
(一)为了解题而解题
(1)三指针一次循环
可以看作有三个区间:全 0 区间、全 1 区间、全 2 区间。
定义三个变量指向(标记)三个区间末尾的下一个位置,看图:

为什么这么安排,先看代码再看几个主要步骤:
class Solution {
public:
void sortColors(vector<int>& nums) {
//0,1,2的指针
int nums0 = 0,nums1 = 0,nums2 = 0;
//数组大小
int n = nums.size();
//遍历计数器
int i = 0;
while(i <= (n - 1))
{
if(nums[i] == 0)
{
nums[nums2++] = 2;
nums[nums1++] = 1;
nums[nums0++] = 0;
}
else if(nums[i] == 1)
{
nums[nums2++] = 2;
nums[nums1++] = 1;
}
else
{
nums[nums2++] = 2;
}
++i;
}
}
};
①假设刚开始有如下数组:

②第一次 while 循环,执行 else 语句:

③第二次 while 循环,执行 else if 语句:


④第三次 while 循环,执行 else 语句:

⑤第四次 while 循环,执行 if 语句:



到这里就基本能了解了。
(2)双指针一次循环(第一种)
根据题目可以知道,最终排好后的数组是 0 全部在数组首部,1 全部在数组中间,2全部在数组尾部。
所以定义一个遍历计数器,再定义两个变量 left 、 right 分别指向数组首尾,计数器往后走,当计数器所在位置元素为 0 则将该数与 left 当前所在位置的元素交换,然后 left 往后走,同理如果计数器所在位置是 2 则将该数与 right 当前所在位置元素交换,然后 right 往前走,直到 i > right 结束循环,其中 0 和 2 排好后,1 自然排到正确的位置。
先看代码再看几个主要步骤:
class Solution {
public:
void sortColors(vector<int>& nums) {
//数组长度
int n = nums.size();
//首尾双指针
int left = 0,right = n - 1;
//遍历计数器
int i = 0;
while(i <= right)
{
if(nums[i] == 0)
{
swap(nums[left++],nums[i++]);//交换后都往后走
}
else if(nums[i] == 2)
{
swap(nums[right--],nums[i]);
}
else ++i;//为 1 直接下一次排序
}
}
private:
void swap(int &a,int &b)
{
int tmp = a;
a = b;
b = tmp;
}
};
有几个细节地方要注意一下,也是我绊倒的地方:
问:循环条件不能是 left < right?
答:有一种情况,比如 10 个数的数组中,只有 2 个 0,5 个 1,3 个 2,头脑快的可以直接想到 left 和 right 永远不会牵手,所有的 0 和 2 分别交换到数组首部和尾部后,left = 2,right = 6,头脑没那么快的看图:
①刚开始:

②中间省略一点步骤,直接到最后一个 2 被交换到数组尾部后的情况,此时 right = 6,可见所有 2 都被交换到了数组尾部,所以 right 不会再移动:

③中间省略一点步骤,直接到最后一个 0 被交换到数组首部后的情况,可见所有 0 都已经交换到数组首部,所以 left 不会再移动,而 left 依旧小于 right,i 也就会继续往后走,但是现在数组已经有序,所以就会出现错误:

④如其中一个错误:

此时 nums[i] = 2,会执行 else if 语句,最终导致错误

问:else 语句可不可以放到最前面?
答:不可以,如果你当前 i 的位置的后面连续几个数刚好是 1 ,0,2,则会出错。看图:
①刚开始:

②第一次循环后:

③第二次循环就满足了1,0,2 的情况,则三个语句都会执行:
第一个 if 条件满足

并且 else if 条件满足

离谱的是 else 也满足了,所以出错了

④第三次循环条件不成立,跳出,得出错误结果
问:循环条件 i <= right 不是多此一举吗?
答:因为 right 指向的是全 2 区间的前一个位置,不在全 2 区间里,也就是说 right 指向的位置的数是没有排序的,所以 i 要走到和 right 同一个位置才算完整。
①刚开始:

②第一次循环:

③第二次循环,此时 i = right 不满足 i < right,循环结束,结果错误。
问:else if 语句中 swap 中的 nums[i] 不可以写成 nums[i++] 吗?
答:不可以,因为你不能保证的当前交换的 right 位置的值就是 0 或者 1,万一是 2,而你 i++,相当于下一次循环就是后面一个位置的数了,从而出错。看图:
①刚开始:

②中间省略一点,直接到第二次循环:

执行 else if 语句,交换后

③第三次循环,也就是最后一次循环,得到的结果显然不正确:

(3)双指针一次循环(第二种)
同样,定义两个标记变量(指针)和一个遍历计数器,不同于第一种的是,两个指针不是一首一尾,而是都从数组首部开始往后走,分别标记全 0 区间和全 1 区间末尾的后一位置。不明白?
先看代码再看几个关键图:
class Solution {
public:
void sortColors(vector<int>& nums) {
//双定位变量
int p0 = 0,p1 = 0;
//遍历计数器
int i;
for(i = 0;i < nums.size()

本文详细探讨了如何通过三指针、双指针(包括一种左闭右开和一种首尾双向)和单指针的方法解决LeetCode 75题的颜色排序问题。讲解了每种解题思路的关键步骤,并揭示了常见陷阱。同时,文中提到了几种排序算法的简化版本,如冒泡排序、选择排序和插入排序,但未涉及归并排序、计数排序和快速排序的错误代码。
&spm=1001.2101.3001.5002&articleId=124653633&d=1&t=3&u=a8879e4cb9de46d69d9548431059d5f5)

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



