n個の数があり(nは一般に非常に大きい)、最大のk個の数を見つける方法は?
アイデア:
ヒープを使用して
1 を実現する。最初にnからk個の数値を選択して、小さなトップヒープを構築します。
2.次に、残りのnk数をヒープの上位要素と順番に比較します。
3.比較ごとに、比較結果に応じて異なる処理が行われます。
1)数値がヒープの一番上の要素より小さい場合、この数値は一番上のkに含まれていてはならず、直接破棄します。
2)数値がヒープの最上位要素より大きい場合、この数値は最上位kにある可能性があり、最上位要素が最上位kに含まれていてはなりません。最上位要素をこの数値に置き換え、ヒープを再調整します。
数値がヒープの先頭要素と同じ場合は、1)または2)のいずれかを実行できます1)ヒープ調整を回避できます。
4.すべての数値を比較した後、ヒープ内の残りの要素はトップ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;
}