系列专栏
目录
1、题目链接
2、题目介绍
给定一个包含红色、白色和蓝色、共 n
个元素的数组 nums
,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0
、 1
和 2
分别表示红色、白色和蓝色。
必须在不使用库内置的 sort 函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0] 输出:[0,0,1,1,2,2]示例 2:
输入:nums = [2,0,1] 输出:[0,1,2]
提示:
n == nums.length
1 <= n <= 300
nums[i]
为0
、1
或2
3、解法
初始化指针:
left
指针
- 指向当前已排序的0(红色)的最后一个元素的下一个位置。
- 初始时,我们还没有排序任何元素,所以
left
设置为-1
。
right
指针
- 指向当前未排序部分的最后一个元素的下一个位置。
- 因为我们要从右向左处理2(蓝色)的元素,所以
right
初始化为nums.size()
。
cur
(当前)指针用于遍历整个数组。它从数组的开头开始,即cur = 0
。
遍历数组:
当
cur
指针没有超出未排序部分的范围时(即cur < right
),进行以下操作:
- 如果
nums[cur] == 0
(红色),则将nums[cur]
与nums[++left]
交换(注意,这里直接赋值而不是交换,因为我们知道left+1
的位置之前都是0或未处理过的元素,直接赋值是安全的)。- 然后,
cur
自增,因为我们已经处理了这个位置。
nums[cur] == 2
(蓝色)由于我们不能立即在
cur
的位置放置2(因为前面可能还有1需要移动到当前位置),所以我们只需将right
减1,并将nums[right]
(原本right
指向的元素,可能是1或未处理的元素)与nums[cur]
交换(但在这个解法中,我们选择不立即交换,而是直接让cur
跳过这个2,稍后通过第二个循环将left+1
到right-1
的所有位置填充为1,而right
及之后的位置则全部为2)。因此,这里我们只减right
,不移动cur
。如果
nums[cur] == 1
(白色),则我们什么都不做,只是将cur
自增。
填充1:
遍历完成后,所有0都已经在数组的开头(
left+1
之前),所有2都已经在数组的末尾(right
及之后)。此时,我们只需要将
left+1
到right-1
的所有位置填充为1即可。因为我们已经知道这部分位置既不是0也不是2,所以它们只能是1。
4、代码
class Solution {
public:
void sortColors(vector<int>& nums) {
//三指针,
//一个遍历,两个划分区域
int left = -1, right = nums.size();
int cur = 0;
while (cur < nums.size())
{
if (nums[cur] == 0)
{
nums[++left] = 0;
}
else if (nums[cur] == 2)
{
right--;//不能修改right指向的元素,因为之后,还要遍历,会影响结果
}
cur++;
}
for (int i = left + 1; i < right; i++)
{
nums[i] = 1;
}
for (int i = right; i < nums.size(); i++)
nums[i] = 2;
}
};