新模版代替
2022-10-10更新
之前快速排序题目整理的链接:
quickSort
利用y总的快排模版更新代替了TopK问题,这样记忆更加方便。
只不过以下是升序,因此求的是第K小的数(只需改一下快排的大小符号即可)
#include<iostream>
using namespace std;
const int N = 100010;
int q[N], n, k;
int quicksort(int l, int r, int k){
if(l == r)return q[l];
// int tmp = rand() % (r-l+1) + 1;
int pivot = q[l+r>>1];
int i = l-1, j = r+1;
while(i < j){
while(q[++i]<pivot);
while(q[--j]>pivot);
if(i<j) swap(q[i], q[j]);
}
int sl = j - l + 1; // 直接记住左侧区间的长度进行比较
if(k <= sl) return quicksort(l,j,k);
else return quicksort(j+1, r, k-sl);
}
int main(){
scanf("%d%d", &n, &k);
for(int i = 0; i < n; i++)
scanf("%d", &q[i]);
printf("%d", quicksort(0, n-1, k));
return 0;
}
TopK问题(旧)
TopK的问题之前做过一次,其实就是快排划分的变种
看过网上一种概念说快排是分而治之,但TopK这个是减治
- 因为快排一分为二后两边都要处理
- TopK的话是只有一半是我们感兴趣的,所以只处理一半
注意
要求第k大,所以我就想着上来先降序排列
然后在比较那里还要注意下标的问题,因为数组从0开始,但k是从1开始的概念
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
return topk(nums, k, 0, nums.size()-1);
}
//l和r是两个端点
int topk(vector<int>& nums, int k, int l, int r){
//每一种情况都有返回值,不考虑l比r大的情况
int n = nums.size();
//加入一个随机选取的操作,先把随机得到的位置换到左端点再划分
int i = rand() % (r - l + 1) + l;
swap(nums[l], nums[i]);
int pos = partition(nums, l, r);
//pos记着和k对齐,即+1
if(pos+1 < k) return topk(nums, k, pos+1, r);
if(pos+1 > k) return topk(nums, k, l, pos-1);
return nums[pos];
}
//划分和快排里的操作一模一样,就是要注意是降序还是升序
int partition(vector<int>& nums, int l, int r){
int key = nums[l];
int low = l, high = r;
while(low < high){
while(nums[high]<=key && low < high)high--;
nums[low] = nums[high];
while(nums[low]>=key && low < high)low++;
nums[high] = nums[low];
}
nums[low] = key;
return low;
}
};
果然随机存取的操作对结果影响还是很大的,在这里展示一下,如果直接取左端点进行划分的话,结果如下:
如果进行随机操作之后:
另外
一定要记得快排划分比较里的“=”,一开始超时我还以为快排这种写法太慢了
结果最后发现是等号没写,蠢到家