75. 颜色分类
给定一个包含红色、白色和蓝色,一共 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.length1 <= n <= 300nums[i]为0、1或2
进阶:
- 你可以不使用代码库中的排序函数来解决这道题吗?
- 你能想出一个仅使用常数空间的一趟扫描算法吗?
搞笑sort
进阶中的最后一句话提醒我们用代码库中的排序函数,直接搞定,当然这不是我们的目的
var sortColors = function (nums) {
return nums.sort((a,b)=>a-b)
}
双指针
思路
我们可以声明两个变量p0和p1用来代表
分界点:
0和1之间的分界点p0
1和2之间的分界点p1
位置区间:
0所在的位置 [0,p0) 不包括p0
1所在的位置[p0,p1)
2所在的位置 [p1,len-1]
具体实现步骤:
-
跟据以上分析,声明p0和p1都从0的位置开始
-
遍历数组nums,拿出第i项的值item
- 如果item===0,此时我们需要把i的值交换到p0的位置,交换完毕后,因为原来p0的位置增加了一个有效数字0,而且p1是在p0之后一定是大于等于p0的,所以p0和p1都需要向后移动
- 如果item===1,需要交换i和p1位置的值,交换完毕后,因为原来p1的位置增加了一个有效数字1,所以p1需要往后挪动一位,而p0因为是在p1之前,所以不需要挪动
-
导致的问题:
- 如果p0不等于p1,证明已经找到过数字1并且交换放入到p1的位置,那么此时,p0必然指向已经排好序的数字1的位置,如果再次发现0并且直接和p0交换,会导致已经拍好序的1又被打乱
- 解决: 因此我们需要在0交换到p0后再讲位于i的数字1重新放入p1的位置
var sortColors = function (nums) {
var p0 = 0
var p1 = 0
for (var i = 0; i < nums.length; i++) {
var item = nums[i]
if (item === 0) {
//交换位置
swap(nums, i, p0)
//如果p0不等于p1则 交换会导致已经整理好的位于p0的1被换走,所以需要再次交换i和p1保证p1都在一起而不会乱
if (p0 !== p1) {
swap(nums, i, p1)
}
//交换后两者位置都要往后移动一位
p0++
p1++
}
if (item === 1) {
swap(nums, i, p1)
p1++
}
}
function swap(nums,i1,i2){
if(i1===i2) return
var temp = nums[i1]
nums[i1] = nums[i2]
nums[i2] = temp
}
};