Sort Colors 分类颜色

给定一个包含红色、白色和蓝色,一共 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

注意:
不能使用代码库中的排序函数来解决这道题。

示例:

输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]

进阶:

  • 一个直观的解决方案是使用计数排序的两趟扫描算法。
    首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

思路一:一次遍历,用三个变量n0,n1,n2分别表示访问到当前下标i时数组中已排序的0,1,2的最右端,如下图所示:


那么有同学就要问了,你这是已经i-1之前的元素已经排序以后的结果指向当然正确了,如果没有排序呢?那么我们就来看下当前下标是如何处理的,因为处理当前的下标的代码如下所示:

if (nums[i] == 0) {
	nums[++n2] = 2;
	nums[++n1] = 1;
	nums[++n0] = 0;
}
else if (nums[i] == 1) {
	nums[++n2] = 2;
	nums[++n1] = 1;
}
else {
	nums[++n2] = 2;
}

因为当前下标的值是1,所以先把n2+1即n2=7,然后赋值为2,同理n1+1后赋值为1,处理过后如图所示:


扫描二维码关注公众号,回复: 2735419 查看本文章

这种方法很巧,相当于通过记录当前n0,n1,n2的右边界,每次根据判断当前下标的值把n0,n1,n2向右移动,这里要注意移动的顺序,必须是先n2,再n1,最后n0,否则会出现数据覆盖的问题。

参考代码:

class Solution {
public:
    void sortColors(vector<int>& nums) {
	int n2 = -1, n1 = -1, n0 = -1,n=nums.size();
	for (int i = 0; i < n; i++) {
		if (nums[i] == 0) {
			nums[++n2] = 2;
			nums[++n1] = 1;
			nums[++n0] = 0;
		}
		else if (nums[i] == 1) {
			nums[++n2] = 2;
			nums[++n1] = 1;
		}
		else {
			nums[++n2] = 2;
		}
	}       
    }
};

思路二:采用荷兰三色旗染色问题,具体思路是把需要染色的部分分成四个部分:

  1. a[1..Lo-1] zeroes (red)
  2. a[Lo..Mid-1] ones (white)
  3. a[Mid..Hi] unknown
  4. a[Hi+1..N] twos (blue)

这里红色表示1,白色表示1,蓝色表示2,我们的目标便是把未知区域的空间压缩到0,初始化lo=0,Mid=0,Hi为nums.size()-1,伪代码如下:

  1. Lo := 1; Mid := 1; Hi := N;
  2. while Mid <= Hi do
    1. Invariant: a[1..Lo-1]=0 and a[Lo..Mid-1]=1 and a[Hi+1..N]=2; a[Mid..Hi] are unknown.
    2. case a[Mid] in
      • 0: swap a[Lo] and a[Mid]; Lo++; Mid++
      • 1: Mid++
      • 2: swap a[Mid] and a[Hi]; Hi–

意思是:每次都判断a[Mid]:

如果是0,那么他应该归属第一区域,所以交换a[Mid]和a[Lo],然后Mid++,Lo++,这样第一区域[0,Lo-1]就包含0

如果是1,应该在第二区域,那么Mid++,这样能保证在第二区域[Lo,Mid-1],而不会在未知区域

如果是2,那么交换a[Mid]和a[Hi],然后Hi--,这样能保证2落在第四区域[Hi+1,N],而不会落在未知区域[Mid,Hi]

这样不断循环知道未知区域的范围是0,便可以完成对三个颜色的划分

参考代码:

class Solution {
public:
    void sortColors(vector<int>& nums) {
	int lo = 0, mid = 0, hi = nums.size() - 1;
	while (mid <= hi) {
		if (nums[mid] == 0) {
			swap(nums[mid], nums[lo]);
			mid++;
			lo++;
		}
		else if (nums[mid] == 1) {
			mid++;
		}
		else {
			swap(nums[mid], nums[hi]);
			hi--;
		}
	}      
    }
};


猜你喜欢

转载自blog.csdn.net/qq_26410101/article/details/80998329