1. 题目
leetcode75_颜色分类
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库内置的 sort 函数的情况下解决这个问题。
例:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
输入:nums = [2,0,1]
输出:[0,1,2]
2. 解法:三分数组
定义循环不变量p0
、p2
、i
,即在循环遍历数组的过程中,这些变量的含义是不变的。
下标在[0, p0)
范围内的数组元素全是0
;
下标在[p0, i)
范围内的数组元素全是1
;
下标在(p2, nums.size() - 1]
范围内的数组元素全是2
。
class Solution {
public:
void sortColors(vector<int>& nums)
{
int p0 = 0;
int p2 = nums.size() - 1;
for (int i = p0; i <= p2;) {
// [0, p0)是0
// [p0, i)是1
// (p2, nums.size() - 1]是2
if (nums[i] == 0) {
swap(nums[i], nums[p0]);
++i;
++p0;
} else if (nums[i] == 2) {
swap(nums[i], nums[p2]);
--p2;
} else {
++i;
}
}
}
};
3. 拓展
相同的三分数组的思路也可以用在快速排序上。即把数组分成小于x
的部分、等于x
的部分、大于x
的部分。
如leetcode215_数组中的第K个最大元素,用快速排序的方式实现如下:
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
return FindNum(nums, 0, nums.size() - 1, nums.size() - k);
}
private:
int FindNum(vector<int>& nums, int left, int right, int k)
{
int pivot = nums[(left + right) / 2];
int less = left;
int equal = left;
int bigger = right;
while (equal <= bigger) {
if (nums[equal] < pivot) {
swap(nums[equal], nums[less]);
++equal;
++less;
} else if (nums[equal] > pivot) {
swap(nums[equal], nums[bigger]);
--bigger;
} else {
++equal;
}
}
--equal;
if (equal < k) {
return FindNum(nums, equal + 1, right, k);
} else if (equal > k) {
return FindNum(nums, left, equal - 1, k);
} else {
return nums[equal];
}
}
};