1.荷兰国旗问题
对应leetcode75. 颜色分类
解题思路:
首先数组中元素有三种 0,1,2 分别代表三种不同的颜色;红,白,蓝;
我们需要选定其中一种元素作为对照值,为什么要选择对照值呢?
比如说,有一个数组:[10,3,2,6,5,11,12,20] 如果我们选择一个对照值 6 ,那么很快就能对数组中的乱序元素进行分类;
将小于6的数放在数组的左边,大于6的数放在 6 的右侧,中间部分放等于6的数值;三个区域就划分好了;小于区,等于区,大于区;
小于区中的数全部是小于对照值的;大于区的数全部是大于对照值的,等于区的数全部是等于对照值的;
荷兰国旗问题就可以参考以上示例,来进行分类;
数组中总共就3种不同的数,0,1,2;很显然选择 1 作为对照值,才能将数组中的各个元素分类;
好了,现在我们已经选择好对照值了,要如何进行分类呢?这才是问题的关键;
给定一个数组[0, 2, 0, 1, 1, 2, 0 ] 我们要如何分类呢?
定义一个小于区的边界left, 定义一个大于区的边界right;
最终数组会变成
综上可以看出无非就是这个套路
- 只要 i 下标位置的值小于对照值,只需将小于区left 右边一位的值和 i 做交换即可; 即swap(arr,left+1,i); 然后小于区外扩,left++,i++;
- 只要 i 下标位置的值等于对照值,小于区和大于区啥也不干,只需要 i++即可;
- 只要 i 下标位置的值大于对照值,那么要将 i 位置的值,和大于区左边一位的值和 i 做交换即可;swap(arr,i,right-1);然后大于区外扩,right--,但 i 不变 (因为新交换过来的值还没有和对照值比较过);
代码如下:
public static void sortColors(int[] nums) {
int left=-1; //小于区
int right=nums.length; // 大于区
int count=0; // 记录等于区的长度
// 循环退出的条件小于区长度+等于区长度等于right;小于区长度为left+1,等于区长度为count,大于区下标为right
for(int i=0; left!=right-1-count;){
// 小于的情况
if(nums[i]<1){
swap(nums,++left,i++);
}else if(nums[i]==1){ // 等于的情况
i++;
count++;
}else{ // 大于的情况
swap(nums,i,--right);
}
}
}
// 交换数组中两个位置的值
public static void swap(int[] arr,int left,int right){
int temp=arr[left];
arr[left]=arr[right];
arr[right]=temp;
}
荷兰国旗问题很重要,彻底弄懂它,才能对付好快速排序的问题; 它的分类思想同样适用于快排;需要彻底攻克它,才能学好快速排序;