现在的位置: 首页 > 综合 > 正文

Leetcode 75 Sort Colors

2013年10月10日 ⁄ 综合 ⁄ 共 2009字 ⁄ 字号 评论关闭

这道题目当然有比较容易想到的方法:首先遍历一遍数组,分别统计0,1,2的个数,然后按照顺序填写在数组相应位置就行了。

这个方法显然需要遍历两次数组,有没有遍历一次就可以的方法呢?
联想到我们在quick sort的时候选取pivot并且partition的思路,我们这里也可以借鉴一下。
不过,知其然,也要知其所以然,一开始按照partition的思路写下了程序,却怎么也通不过,仔细研究了一下,才发现对quick sort的理解不够深刻啊。
这里首先说一下partition的思路。我们首先随机选取一个pivot,并且将其放在某一个位置(一般为start位置),随后用两个指针。quicksortp1指针从start+1的位置开始,指向第一个不比pivot小的元素,quicksortp2指针也从start+1的位置开始,指向当前我们遍历的位置。所以,quicksortp2一定是大于等于quicksortp1的。每当quicksortp2遇到一个元素,就和pivot进行比较,如果比pivot小,那么就交换quicksortp1和quicksortp2指向的元素。(重点1)这样遍历完数组之后,交换pivot和quicksortp1-1位置的元素(因为quicksortp1指向第一个不比pivot小的元素,那么quicksortp1-1指向的元素一定比pivot小,这样就可以把pivot放在中间,达到二分的目的了——pivot左边的元素都比它小,右边的元素都不比它小)
这里,重点来了。参考(重点1)位置,为什么交换quicksortp1和quicksortp2元素之后,就能保证pivot一定在中间呢?
道理的确很简单,因为我们是“二分”如果一个元素不比pivot小,那么就一定大于等于pivot,所以,quicksortp1指针的含义不仅仅是指向第一个不比pivot小的元素,更重要的意义在于:它是一个分界线,分开了比pivot小和不比pivot小的元素。

那么回到我们这个题目中来。如果我们想遍历一次数组,那么我们就应该设置三个指针。第一个p1指向0元素的结尾,第二个p2指向2元素的开始,第三个p3用来遍历整个数组。那么我们应该怎样做?首先,p1和p3指向数组开始,p2指向数组结尾。如果p3指向的位置是一个0,那么交换p1和p3指向的元素。如果该元素是2,那么交换p2和p3指向的元素。每次p3都自增1,这样遍历完整个数组(实际上,遍历到p2位置就可以),我们的任务就做完了。
按照这个思路写出来程序,竟然有错误!为什么?
我们先回头看一下quick sort中的做法。为什么每次交换之后,我们能够放心大胆的让quicksortp2继续向前遍历?因为我们知道,我们现在是二分数组,如果当前元素比pivot小,那么交换过来的元素,就一定大于等于pivot!
再看看leetcode这道题目,我们有这样的保证吗?答案是没有。比如p3和p1交换完毕之后,交换的元素是什么?有两种可能:一种是1,一种是2。所以,这里我们就要判断一下交换过来的元素是什么,因为没有办法保证当前交换完毕的元素,一定符合我们的需要。换句话说,我们交换完毕之后,还要判断一下当前元素是什么。如果是2的话,就继续交换。
那么这样可就复杂了,我们不如换一个思路:还是用三个指针,但是我们的定义变一下。p1指向1元素的开始,作为0和1的分界点。p2指向1元素的结尾,作为1和2的分界点。p3用来遍历。
遍历的时候采取这样的策略:如果p3指向的元素为0,那么交换p3和p1位置的元素。因为刚刚的定义,所以我们总是能够保证交换过来的元素是1,那这样的话我们就p1++,p3++。如果p3指向的元素是2,那么我们交换p2和p3指向的元素,p2--,但是p3不变,因为我们不知道交换过来的是什么元素。
这样遍历一边数组之后,就能够得到我们想要的结果了。

class Solution
{
public:
#define RED 0
#define WHITE 1
#define BLUE 2
	void sortColors(int A[], int n)
	{
		if (A == NULL)
			return;
		int redIndex = 0; //points to the first one that may be not red
		int blueIndex = n - 1; //points to the first one that may be not blue
		int index = 0;
		while (index <= blueIndex)
		{
			if (A[index] == RED)
			{
				swap(A[index], A[redIndex]);
				redIndex++;
				index++; //cannot be less than redIndex
			}
			else if (A[index] == BLUE)
			{
				swap(A[index], A[blueIndex]);
				blueIndex--;
			}
			else
				index++;
		}

	}
};

抱歉!评论已关闭.