此题就是“荷兰国旗问题”,题目如下:
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
思路一:
最先想到的肯定是排序算法,快排和计数排序。
快排代码
class Solution {
public:
void sortColors(vector<int>& nums) {
quick_sort(nums,0,nums.size()-1);
}
void quick_sort(vector<int>& nums,int l ,int r)
{
if(l >= r)return;
int i = l-1,j = r+1,k = nums[l+r>>1];
while(i < j)
{
do(i++);while(nums[i] < k);
do(j--);while(nums[j] > k);
if(i < j)swap(nums[i],nums[j]);
}
quick_sort(nums,l,j);
quick_sort(nums,j+1,r);
}
};
计数排序
class Solution {
public:
void sortColors(vector<int>& nums) {
int i = 0,j = 0,k = 0, n = nums.size();
for(int m = 0;m < n;m++)
{
if(nums[m] == 0)
i++;
if(nums[m] == 1)
j++;
if(nums[m] == 2)
k++;
}
for(int m = 0;m < n;m++)
{
if(m < i)
nums[m] = 0;
if( m >= i && m < i+j)
nums[m] = 1;
if(m >= i+j && m < n)
nums[m] = 2;
}
}
};
两个都是4ms,只击败了40%
思路二:
利用双指针的思路:遍历第一遍,将 0 全部移动到最前面,与非0的交换位置;
遍历(其实不算遍历,从不是0的后一个开始,继续将 1 移动),最后的2就自然到最后面了。
class Solution {
public:
void sortColors(vector<int>& nums) {
int len = nums.size();
int l = 0,r = 0;
for(l = 0,r = 0;r < len;r++)
{
if(nums[r] == 0)
swap(nums[l++],nums[r]);
}
for(r = l;r < len;r++)
{
if(nums[r] == 1)
swap(nums[l++],nums[r]);
}
}
};
再优化一下,使得只要遍历一遍:
思路:我们用三个指针,第一个指针 i 用于遍历整个数组,另外两个指针分别用于交换1,0与 num[i] 的位置。
我们要注意:
指向 1 的指针不能慢于指向 0 的,否则会出现前面排好序的 0 被一个 1给 交 换位置了;
class Solution {
public:
void sortColors(vector<int>& nums) {
int len = nums.size();
int l = 0,r = 0;
for(int i = 0;i < len ;i++)
{
if(nums[i] == 1)
{
swap(nums[i],nums[l++]);
}
else if(nums[i] == 0)
{
swap(nums[i],nums[r]);
if(r < l)
{
swap(nums[i] ,nums[l]);
}
r++;
l++;
}
}
}
};