1、题目描述
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
进阶:
一个直观的解决方案是使用计数排序的两趟扫描算法。
首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
你能想出一个仅使用常数空间的一趟扫描算法吗?
2、示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
3、题解
基本思想:荷兰国旗问题,三指针,一次遍历,如果是0,则移动到表头,如果是2,则移动到表尾,不用考虑1。这种思想和快速排序思想有点像,快速排序(Quick Sort)的基本思想是通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。
- left指向0的右边界,right指向2的左边界,也就是通过left和right将三色隔离红色[0,left)白色[left,right]蓝色(righ,n-1]
- 当前元素为0,需要跟0的右边界left交换,0的右边界left++,cur++
- 当前元素为1,cur一直位于left与right之间的1元素上,所以不需要交换,cur++
- 当前元素为2,需要跟2的左边界right交换,2的左边界right--
#include<iostream>
#include<vector>
#include<algorithm>
#include<iterator>
using namespace std;
class Solution {
public:
void sortColors(vector<int>& nums) {
//基本思想:荷兰国旗问题,三指针,一次遍历,如果是0,则移动到表头,如果是2,则移动到表尾,不用考虑1
//left指向0的右边界,right指向2的左边界,也就是通过left和right将三色隔离红色[0,left)白色[left,right]蓝色(righ,n-1]
int left, right, cur;
left = 0;
right = nums.size() - 1;
cur = 0;
while (cur <= right)
{
//当前元素为0,需要跟0的右边界left交换,0的右边界left++,cur++
if (nums[cur] == 0)
{
swap(nums[cur], nums[left]);
left++;
cur++;
}
//当前元素为1,cur一直位于left与right之间的1元素上,所以不需要交换,cur++
else if (nums[cur] == 1)
{
cur++;
}
//当前元素为2,需要跟2的左边界right交换,2的左边界right--
else
{
swap(nums[cur], nums[right]);
right--;
}
}
return;
}
};
int main()
{
Solution solute;
vector<int> nums = { 2,0,2,1,1,0 };
solute.sortColors(nums);
copy(nums.begin(), nums.end(), ostream_iterator<int>(cout, " "));
return 0;
}