算法思想
- 快速排序在每一轮挑选一个基准元素,并让其他比它大的元素移动到右边,比它小的移动到左边,从而把数列拆分成两部分.
- 与归并排序算法一样,快速排序算法也是分治策略的典型应用,但二者之间也有本质的区别.归并排序的计算量主要消耗于有序子向量的归并操作,而子向量的划分却几乎不费时间.快速排序恰恰相反,它可以在O(1)时间内,由子问题的解直接得到原问题的解;但为了原问题划分为两个子问题,却需要O(n)时间.
算法模版
递归版本:
void quickSort(vector<int>& nums,int l,int r){
if(l >= r) return ;
int i = l - 1,j = r + 1,pivot = nums[rand() % (r - l + 1) + l]; // 小于区域,大于区域,基准
while(i < j){
do i++; while(nums[i] < pivot);
do j--; while(nums[j] > pivot);
if(i < j) swap(nums[i],nums[j]);
}
quickSort(nums,l,j);
quickSort(nums,j + 1,r);
}
非递归版本(使用栈来模拟递归的调用栈):
void quick_nr(vector<int>& nums,int l,int r) {
// struct Element { int l; int r; };
stack<pair<int,int>> s; // l , r
s.push({l , r}); // 初始状态
while(!s.empty()){
auto [l , r] = s.top();
s.pop(); // 取出栈顶
if(l >= r) continue;
int i = l - 1,j = r + 1;
int pivot = nums[rand() % (r - l + 1) + l];
while(i < j){
do i++; while(nums[i] < pivot);
do j--; while(nums[j] > pivot);
if(i < j) swap(nums[i],nums[j]);
}
s.push({j + 1,r});
s.push({l , j});
}
}
算法应用
- 荷兰国旗问题
75. 颜色分类
class Solution {
public:
void sortColors(vector<int>& nums) {
int l = -1,r = nums.size(), pivot = 1; // 小于区域,大于区域,pivot
int i = 0;
while(i < r){
if(nums[i] == pivot) i++;
else if(nums[i] < pivot) swap(nums[i++],nums[++l]);
else swap(nums[i],nums[--r]);
}
}
};
将数组中的大小写字母分开
void partition(vector<char>& nums,int l,int r){
if(l >= r) return ;
int i = l - 1,j = r + 1;
while(i < j){
do i++; while(islower(nums[i]));
do j--; while(isupper(nums[j]));
if(i < j) swap(nums[i],nums[j]);
}
}
- Top K问题