【leetcode】75. 颜色分类
题目内容
思路分析
方法一:单指针
可以采用一个单指针ptr,来表征“头部区域”的范围。遍历两遍数组:
- 第一遍:遇到0则将0放进“头部区域”,即交换nums[i]和nums[ptr],并将ptr+1;
- 第二遍:遇到1则将1放进“头部区域”,即交换nums[i]和nums[ptr],并将ptr+1。
经过这样的两遍遍历,即可把乱序的0,1,2数组重新排序好。
方法二:双指针
方法一要遍历两次数组,比较蠢,所以使用双指针来进行优化。
类似方法一,设两个指针。指针ptr0表示已排好序的0的范围,指针ptr1表示已排好序的0+已排好序的1的范围。
遍历一次数组:
-
如果遇到1则与方法一一样,交换并将ptr1+1;
-
如果遇到0则需要进行特殊处理。
当ptr1>ptr0时,表示已经排好序的0后有排好序的1,这时交换nums[i]和nums[ptr0]后,会把一个已经排好序的1换出去。因此需要再交换nums[i](这时nums[i]已经变成了换出去的1)和nums[ptr1]。
当ptr1=ptr0时,表示已经排好序的0后没有排好序的1,不需要再做特殊处理。
不论ptr1>ptr0还是ptr1=ptr0,都需要将两个指针加1。
参考资料中的动图还不错,可以便于理解。
代码
#include <vector>
#include <math.h>
#include <limits.h>
#include <utility>
using namespace std;
// 【错误】面对[1,0,1]这种情况无能为力
// 双指针(快排思想)
// 时间复杂度O(n)
// 空间复杂度O(1)
class Solution1 {
public:
void sortColors(vector<int>& nums) {
int pivot = 1;
int i{ 0 };
int j = nums.size() - 1;
while(i != j) {
while (i < j && nums[j] > pivot) {
j--;
}
while (i < j && nums[i] <= pivot) {
i++;
}
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
}
for (int k = 0; k < nums.size(); ++k) {
if (nums[k] == pivot) {
nums[k] = nums[i];
nums[i] = pivot;
break;
}
}
}
};
// 单指针
// 时间复杂度O(n)
// 空间复杂度O(1)
class Solution2 {
public:
void sortColors(vector<int>& nums) {
int n = nums.size();
int ptr = 0;
for (int i = 0; i < n; ++i) {
if (nums[i] == 0) {
swap(nums[i], nums[ptr]);
++ptr;
}
}
for (int i = 0; i < n; ++i) {
if (nums[i] == 1) {
swap(nums[i], nums[ptr]);
++ptr;
}
}
}
};
// 双指针
// 时间复杂度O(n)
// 空间复杂度O(1)
class Solution {
public:
void sortColors(vector<int>& nums) {
int n = nums.size();
int ptr0 = 0, ptr1 = 0;
for (int i = 0; i < n; ++i) {
if (nums[i] == 0) {
swap(nums[i], nums[ptr0]);
if (ptr1 > ptr0) {
swap(nums[i], nums[ptr1]);
}
++ptr0;
++ptr1;
} else if (nums[i] == 1) {
swap(nums[i], nums[ptr1]);
++ptr1;
}
}
}
};
int main() {
Solution s;
vector<int> input{ 2,0,2,1,1,0 };
s.sortColors(input);
int a = 0;
}
收获
- 一道题分几天做很恶心