这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
前言
关于 LeetCode 数组类型题目的相关解法,可见LeetCode 数组类型题目做前必看,分类别解法总结了题目,可以用来单项提高。觉得有帮助的话,记得多多点赞关注哦,感谢!
题目描述
给定一个包含红色、白色和蓝色,一共 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]
链接:leetcode-cn.com/problems/so…
题解
这道题目是很有名的“荷兰国旗”问题,题目大意是0,1,2三个数组组成的数组,对其进行排序。 如果我们粗暴的用内置 sort 函数对其进行排序,那么时间复杂度为 O(nlogn), 那么对于只有三个数的排序来说,这种解法就显得大材小用。
其实看到题目的第一个想法是统计 0,1,2 每个数字出现的次数,然后重新放置回数组中,这种方法违背了原地排序的原则。
然后我们进一步想,我们遍历数组,用一个变量记录数字 0 部分最后一个下标,遍历过程中,遇到 0 就和前面的部分交换,变量加 1, 那么我们遍历一遍,数组前面一部分就已经是 0 了, 然后我们再从 0 之后的部分开始遍历,寻找 1 来交换,最后数组就是有序的了,时间复杂度为 O(n)。 代码如下:
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var sortColors = function(nums) {
let ptr = 0
for (let i = 0; i < nums.length; i++) {
if (nums[i] === 0) {
swap(nums, i, ptr)
ptr++
}
}
for (let i = ptr; i < nums.length; i++) {
if (nums[i] === 1) {
swap(nums, i, ptr)
ptr++
}
}
};
var swap = (nums, i, j) => {
let tmp = nums[i]
nums[i] = nums[j]
nums[j] = tmp
}
上面的方法用到了两次遍历,那么可以不可以只用一次遍历来解决这个问题呢?我们可以想到双指针来解决单指针记录不足的问题,加上一个从右向左扩展的指针来记录数字 2,从左到右的扩展的指针记录数字 1,这样一次遍历就可以排好序了。代码如下:
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var sortColors = function(nums) {
let left = cur = 0
let right = nums.length - 1
while (cur <= right) {
if (nums[cur] === 0) {
swap(nums, left, cur)
left++
cur++
} else if (nums[cur] === 1) {
cur ++
} else {
swap(nums, cur, right)
right--
}
}
}
var swap = (nums, i, j) => {
let tmp = nums[i]
nums[i] = nums[j]
nums[j] = tmp
}