有n个(n一般很大)的数,从中求出最大的k个,怎么求?
思路:
用堆实现
1.先从n中随便选k个数,建成一个小顶堆。
2.然后把剩下的n-k个数,依次与堆顶元素比较。
3.每次比较,根据比较结果做不同的处理。
1)如果数比堆顶元素小,那么这个数一定不是top k中的,直接舍弃。
2)如果数比堆顶元素大,那么这个数是可能是top k中的,堆顶元素一定不是top k中的,用这个数替换堆顶元素,然后重新调整堆。
如果数与堆顶元素相同,执行1)或2)都可,1)可以避免调整堆。
4.所有的数比较完后,堆中剩下的元素就是top k。
时间复杂度:
建堆时,每加入一个元素耗时logk。比较时,每次比较耗时logk。建队时加入元素次数+比较次数=n。时间复杂度为O(n log k)
空间复杂度:
堆的大小,O(k)
c++实现:
#include <queue>
#include <vector>
#include <cstdio>
using namespace std;
void topK(const vector<int> & input ,vector<int> & result, int k){
priority_queue<int, vector<int>,greater<int>> pq;
for(int i=0; i<k; i++)
pq.push(input[i]);
for(int i=k; i<input.size(); i++){
if(input[i]<=pq.top())
;
else if(input[i]>pq.top()){
pq.pop();
pq.push(input[i]);
}
}
result.clear();
for(int i=0; i<k; i++) {
result.push_back(pq.top());
pq.pop();
}
}
int main() {
vector<int> input;
vector<int> result;
int t,n,k;
scanf("%d%d", &n, &k);
while(scanf("%d", &t)==1)
input.push_back(t);
topK(input, result, k);
for(auto it=result.begin(); it!=result.end(); it++)
printf("%d ", *it);
printf("\n");
return 0;
}