75. 颜色分类
题目
给定一个包含红色、白色和蓝色、共 n
个元素的数组 nums
,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0
、 1
和 2
分别表示红色、白色和蓝色。
必须在不使用库内置的 sort 函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1]
输出:[0,1,2]
提示:
n == nums.length
1 <= n <= 300
nums[i]
为0
、1
或2
思路
借用了外部空间解决,次一档的做法。
class Solution {
public void sortColors(int[] nums) {
// 左指针记录0要补充的位置,右指针记录2要补充的位置
int i = 0, j = nums.length - 1;
int[] ans = new int[nums.length];
for (int index = 0; index < nums.length; index++) {
if (nums[index] == 0) {
ans[i++] = nums[index];
} else if (nums[index] == 2) {
ans[j--] = nums[index];
}
}
while (i <= j) {
ans[i++] = 1;
}
System.arraycopy(ans, 0, nums, 0, nums.length);
}
}
但还有另一个不借助外部空间、且只需要O(1)的方法,75. 颜色分类 - O(n) 插入排序,简洁写法
需要借助一个O(1)插入元素的方法,虽然是别人的,但在我这里自己总结归纳一下
以[0,0,1,1,2,2]
为例,向其中插入一个0,并且保持有序,要怎么做?
直觉上,当然是在最后一位0之后插入,然后后面的元素依次向后挪一位。
但如果我们仔细观察,会发现其实只有3个元素需要改变,分别是下图中绿色圈的这3个元素
所以可以看出,重复的元素中间部分是不需要改变的,只有首尾会变。由此,我们可以用三个变量分别记录每个元素结束的下一位指针,比如P0是元素0结束的下一位指针。
再插入0时,只需要把P0改成0,P1改成1,P3加上2即可。
有个特殊的逻辑处理,就是当元素如果只有0和1时,最后一步补2就不对了。但是也不需要用ifelse处理特殊情况,这里的逻辑都是把元素末尾加上了一个自身元素,所以我们可以把P2加上2之后,继续把P1改成1,P0改成0,这样子,如果只有0和1,就会覆盖P2的结果。
public void sortColors(int[] nums) {
int p0 = 0, p1 = 0;
for (int index = 0; index < nums.length; index++) {
int num = nums[index];
nums[index] = 2;// p2赋值2
if (num <= 1) {
nums[p1++] = 1;// p1赋值1
}
if (num == 0) {
nums[p0++]=0;// p0赋值0
}
}
}