「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」
前言
力扣第七十五题 颜色分类 如下所示:
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地**对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
示例 1:
输入: nums = [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]
示例 2:
输入: nums = [2,0,1]
输出: [0,1,2]
进阶:
- 你可以不使用代码库中的排序函数来解决这道题吗?
- 你能想出一个仅使用常数空间的一趟扫描算法吗?
一、思路
这一题题目意思比较简单,就是将数组中的0 1 2 按升序排列
如果不考虑到一趟扫描的话,我们可以先遍历一遍数组,记下 0 1 2 的个数,再根据它们的个数来修改原来的数组即可。伪代码如下所示:
public void sortColors(int[] nums) {
int zeroCnt = oneCnt = twoCnt = 0;
// 遍历并计数
for (i=0; i<nums.len; i++) {
if(nums[i] == 0)
zeroCnt++;
else if(nums[i] == 1)
oneCnt++;
else twoCnt++;
}
// 原地修改
for (i=0; i<nums.len; i++) {
if(zeroCnt > 0) {
nums[i] = 0;
zeroCnt--;
} else if(oneCnt > 0){
nums[i] = 1;
oneCnt--;
} else{
nums[i] = 2;
twoCnt--;
}
}
}
既然要一趟遍历就完成排序的处理,我们不妨使用两个变量 p0 和 p1 来存储最后一个 0 和 1 的位置。
在遍历数组的时候,有如下三种情况
- 碰到0:交换
nums[i] 和 nums[++p0]。如果交换后p1 > p0说明交换的是1,再将nums[++p1]和nums[i]交换(不要让连续的1断开) - 碰到1:如果
p1 < p0,则将p1 = po(保证1在0的后面)。再交换 nums[i] 和 nums[++p1] - 碰到2:不做任何处理
举个例子
此处以 nums = [2,0,2,1,1,0] 作为例子
- 初始化变量
p0 = p1 = -1 - 遍历数组,
nums[0] == 2不做任何处理 nums[1] == 0,交换nums[0] 和 nums[1],数组变成[0,2,2,1,1,0],p0 = 1nums[2] == 0,nums[2] == 2不做任何处理nums[3] == 1,此时p1 < p0则将p1 = p0 = 0,再交换nums[1] 和 nums[3],数组变成[0,1,2,2,1,0]nums[4] == 1,交换nums[2] 和 nums[4],数组变成[0,1,1,2,2,0]nums[5] == 0,交换nums[1] 和 nums[5],数组变成[0,0,1,2,2,1]。再将移动后面的1补到连续1的后面即可。数组变为[0,0,1,1,2,2]
二、实现
实现代码
实现代码与思路中保持一致
public void sortColors(int[] nums) {
int len = nums.length;
int p0 = -1, p1 = -1;
for (int i = 0; i < len; i++) {
if (nums[i] == 0) { // 碰到0就交换
nums[i] = nums[++p0];
nums[p0] = 0;
// 如果交换过来的是 1
if (p0 <= p1) {
// 将交换过来的1移到1的最后面
nums[i] = nums[++p1];
nums[p1] = 1;
}
} else if (nums[i] == 1) {
if (p1 < p0)
p1 = p0;
nums[i] = nums[++p1];
nums[p1] = 1;
}
}
}
测试代码
public static void main(String[] args) {
int[] nums = {2,0,2,1,1,0};
new Number75().sortColors(nums);
System.out.println(nums);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~