题目介绍
这道题是LeetCode75. 颜色分类,难度medium。
给定一个包含红色、白色和蓝色,一共 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]
示例 3:
输入:nums = [0]
输出:[0]
示例 4:
输入:nums = [1]
输出:[1]
提示:
- n == nums.length
- 1 <= n <= 300
- nums[i] 为 0、1 或 2
进阶:
- 你可以不使用代码库中的排序函数来解决这道题吗?
- 你能想出一个仅使用常数空间的一趟扫描算法吗?
解题思路
根据题目的要求,就是将给定数组nums按照0, 1, 2的顺序排序后返回,要仔细审题,注意这里是原地对它们进行排序,所以不要上来就是循环nums,然后将0, 1, 2依次添加到新数组之后返回,这样是不符合要求的。
原地那就是让我们来用指针的方法交换数组了。
单指针
设定一个指针ptr = 0,然后先循环nums数组,找到每个0和ptr交换,每交换一次ptr++,循环结束后nums数组的头部都是0。
然后从ptr开始再次循环nums数组(因为ptr之前的都是0),找个每个1和ptr交换,没交换一次ptr++,循环结束后的nums数组就是我们想要的结果数组了。
时间复杂度:O(n)O(n),其中 nn 是数组 \textit{nums}nums 的长度。
空间复杂度:O(1)O(1)。
双指针
单指针是用一个指针ptr循环两次,那我们可不可以只循环一次呢?
当然可以,设定两个指针p0 = 0, p1 = 0,然后循环nums数组,如果遇见0的话我们将i和p0交换,注意这里,因为我们是按照0, 1, 2的顺序来排序的,所以0之后都是1,这里我们可能会把1交换出去,所以这里当p0 < p1的时候,我们还需要将i和p1交换,然后p0++; p1++。
如果我们遇见1,那么就跟单指针的方法一样,将p1和i进行交换,然后p1++;
这样最后我们就得到了我们想要的数组。
左右双指针
上一步中我们是用双指针从左到右遍历nums数组的,我们也可以从两端开始遍历,设定left = 0和right = nums.length - 1,当从左到右超过了right的时候就可以停止遍历了。
当遇见0的时候,i和left交换,然后left++。
当遇见2的时候,i和right交换,然后right--。
1保持不变,遍历结束后的数组nums就是我们需要的结果数组了。
解题代码
单指针
var sortColors = function(nums) {
const n = nums.length;
let ptr = 0;
for (let i = 0; i < n; i++) {
if (nums[i] === 0) {
[nums[i], nums[ptr]] = [nums[ptr], nums[i]];
ptr++;
}
}
for (let i = ptr; i < n; i++) {
if (nums[i] === 1) {
[nums[i], nums[ptr]] = [nums[ptr], nums[i]];
ptr++;
}
}
return nums;
}
双指针
var sortColors1 = function(nums) {
const n = nums.length;
let p0 = 0, p1 = 0;
for (let i = 0; i < n; i++) {
if (nums[i] === 1) {
[nums[i], nums[p1]] = [nums[p1], nums[i]];
p1++;
} else if (nums[i] === 0) {
[nums[i], nums[p0]] = [nums[p0], nums[i]];
if (p0 < p1) {
[nums[i], nums[p1]] = [nums[p1], nums[i]];
}
p0++;
p1++;
}
}
return nums;
}
两端双指针
var sortColors2 = function(nums) {
const n = nums.length;
let left = 0, right = n - 1;
let i = 0;
while(i <= right) {
while(i <= right && nums[i] === 2) {
[nums[i], nums[right]] = [nums[right], nums[i]];
right--;
}
if (nums[i] === 0) {
[nums[i], nums[left]] = [nums[left], nums[i]];
left++;
}
i++;
}
return nums;
}
刷题打卡记录
这里是之前的刷题打卡记录,大家有兴趣的可以看下,如果有什么不同的见解和看法或者觉得有什么错误的,欢迎在评论区留言!🙏🙏🙏
[LeetCode0303题区域和检索 - 数组不可变] | 刷题打卡
[LeetCode0304题二维区域和检索 - 矩阵不可变] | 刷题打卡
[LeetCode236题二叉树的最近公共祖先] | 刷题打卡
[LeetCode1124题表现良好的最长时间段] | 刷题打卡
[LeetCode1047题删除字符串中的所有相邻重复项] | 刷题打卡
[LeetCode1438题绝对差不超过限制的最长连续子数组] | 刷题打卡
总结
加油!hxdm!!!💪💪💪
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情