1.暴力
直接使用sort
sort(arr.begin(),arr.end());
2.堆/优先级队列
依次弹出即可,这种方法也适合求第k个最大的元素,且要求每个元素都不相同。
int num = 0;
vector<int> res(k, 0); //初始化为有k个空间,默认值为0的数组
if(k == 0) return res;
priority_queue<int,vector<int>,greater<int>> q;//greater也就意味着大的在后面
for(auto item:arr) q.push(item);
while(!q.empty() && num < k){
res[num] = q.top();
q.pop();
num++;
}
return res;
3.快速排序变种
//这里使用覆盖的方法(自己起的,另外一个是交换)
int Partition(vector<int> &arr,int left,int right){
if(left == right) return left;
//以最左边作为中轴,此时的中值就是tmp
int tmp = arr[left];
while(left < right){
while(left < right && arr[right] >= tmp) right--;
//右边存在比中值大的,将其放到左边。
arr[left] = arr[right];
while(left < right && arr[left] <= tmp) left++;
//左边存在比中值小的,将其放到右边。
arr[right] = arr[left];
}
arr[left] = tmp;
//返回最后的分界点
return left;
}
//递归实现
void quicksort(vector<int> &arr,int left,int right,int k){
if(left < right){
int pos = Partition(arr,left,right);
//如果中轴在k处,直接返回
if(pos == k) return;
quicksort(arr,left,pos-1,k);
quicksort(arr,pos+1,right,k);
}
}
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int> res(k,0);
quicksort(arr,0,arr.size()-1,k);
for(int i = 0;i<k;i++) res[i] = arr[i];
return res;
}
4.nth_element
nth_element(arr.begin(), arr.begin() + k, arr.end(),cmp);
不保证前一段和后一段有序
5.Hash
在数值不大的时候,可以使用hash的方式进行存储,之后依次读即可。这个也适用于求第k大,但是每个元素不同的情况.
int num = 0;
map<int,int> m;
vector<int> res(k,0);
for(int i = 0;i<arr.size();i++){
m[arr[i]]++;
}
for(auto item:m){
//需要注意,要每次将数字减一
while(item.second > 0){
if(num >= k) break;
res[num++] = item.first;
item.second--;
}
}
return res;
6.总结
其实都差不多,总体上就两个思路,快排和hash。其他都是这两个衍生出来的。正常情况下,直接怼快排即可。因为其时间复杂度低。