75.颜色分类
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意:
不能使用代码库中的排序函数来解决这道题。
示例:
输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
思路
这题目乍一看还没看懂,我还以为就是一个升序排序问题,看了下应该是一个分类的问题,将相同类别合并到一起,感觉跟最近学的机器学习挺像的将数字啥的聚类。这里还是比较简单,就三种类别,然后又是数组的题目,一般就是用双指针或者多指针来解决问题,这里也是用双指针的解法。
这里我们只要界定了0和2的边界,那么1也就自然排序好了。
1、将0的边界指向数组第一个元素
2、将2的边界指向数组的最后一个元素
3、从头到尾开始遍历数组
- 如果当前值是0,就和0边界的元素交换
- 如果当前值是2,就和2边界的元素交换
- 如果当前值是1,就检索下一个元素
- 如果处理完后当前检索位置大于等于p2的位置那么就退出程序
代码实现
class Solution {
public void sortColors(int[] nums) {
int p0 = 0, p2 = nums.length - 1;
for(int i = 0; i < nums.length; i++)
{
if(nums[i] == 0)
{
swap(nums,i,p0);
p0++;
}else if(nums[i] == 2)
{
swap(nums,i--,p2);
p2--;
}
if(i >= p2)
break;
}
}
//交换数组的第a个数和第b个数
private void swap(int[] nums,int a,int b)
{
if(a == b || nums[a] == nums[b])
return;
nums[a] = nums[a] + nums[b];
nums[b] = nums[a] - nums[b];
nums[a] = nums[a] - nums[b];
}
}
这里有点点细节需要考虑:
假如初始化是:{1,2,0},p0 = 0,p2 = 2, i = 0
第一次交换后是:{1,2,0},p0 = 0, p2 = 2, i = 1,
第二次交换后是:{1,0,2},p0 = 0, p2 = 1, i = 2,这时候 i >= p2理应退出遍历,但是我们发现0其实我们是没有处理过的,它是被交换到数组中的位置1处的,所以这个时候我们不能将i++,但是我写的for循环里面写了++,所以在向后交换的时候加上了i–来抵消i++,如下情况:
if(nums[i] == 0)
{
swap(nums,i,p0);//向前交换不用考虑
p0++;
}else if(nums[i] == 2)
{
swap(nums,i--,p2);//向后交换,再处理一边交换过来的数
p2--;
}