荷兰国旗问题

问题描述:

现有红白蓝三个不同颜色的小球,乱序排列在一起,请重新排列这些小球,使得红白蓝三色的同颜色的球在一起。这个问题之所以叫荷兰国旗问题,是因为我们可以将红白蓝三色小球想象成条状物,有序排列后正好组成荷兰国旗。

分析

这个问题我们可以将这个问题视为一个数组排序问题。红白蓝分别对应数字0、1、2。红、白、蓝三色小球数量并不一定相同。
 

1020112021
0001111222

数据如第一行所示,排序之后结果为第二行。 这个问题就是一个排序问题。需要把小于1的放在前面,1放在中间,2放在最后。
我们接下来看看如何解决这个问题。

解法一:

1.遍历数组,统计红白蓝三色球(0,1,2)的个数

2.根据红白蓝三色球(0,1,2)的个数重排数组

时间复杂度为O(n)

代码如下:

class Solution {
	public void sortColors(int arr[]) {
		if (arr.length <= 1) {
			return;
		}
		// 统计个数
		int red = 0, white = 0, blue = 0;
		for (int i = 0; i < arr.length; ++i) {
			if (arr[i] == 0) {
				++red;
			} else if (arr[i] == 1) {
				++white;
			} else {
				++blue;
			}
		}
		// 重新布局
		for (int i = 0; i < arr.length; ++i) {
			if (red > 0) {
				arr[i] = 0;
				--red;
			} // if
			else if (white > 0) {
				arr[i] = 1;
				--white;
			} // else
			else {
				arr[i] = 2;
			}
		}
	}
}

解法二:

我们可以把数组分成三部分,前部(全部是0),中部(全部是1)和后部(全部是2)三个部分,每一个元素(红白蓝分别对应0、1、2)必属于其中之一。

将前部和后部各排在数组的前边和后边,中部自然就排好了。

设置两个指针begin指向前部的末尾的下一个元素(刚开始默认前部无0,所以指向第一个位置),end指向后部开头的前一个位置(刚开始默认后部无2,所以指向最后一个位置),然后设置一个遍历指针i,从头开始进行遍历。

(1)若遍历到的位置为1,则说明它一定属于中部,根据总思路,中部的我们都不动,然后i向前移动一个位置。

(2)若遍历到的位置为0,则说明它一定属于前部,于是就和begin位置进行交换,然后i向前移动一个位置,begin也向前移动一个位置(表示前边的已经都排好了)。

(3)若遍历到的位置为2,则说明它一定属于后部,于是就和end位置进行交换,由于交换完毕后i指向的可能是属于前部的,若此时i前进则会导致该位置不能被交换到前部,所以此时i不前进。而同1),end向前移动一个位置。
代码如下:

class Solution {
	public void sortColors(int arr[]) {
		int begin = 0, end = arr.length - 1, i = 0, temp;
		while (i <= end) {
			if (arr[i] == 0) {
				temp = arr[begin];
				arr[begin] = arr[i];
				arr[i] = temp;
				++begin;
				++i;
			} else if (arr[i] == 1) {
				++i;
			} else {
				temp = arr[i];
				arr[i] = arr[end];
				arr[end] = temp;
				--end;
			}
		}

	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值