top k问题的一种解法。

有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;
}

猜你喜欢

转载自blog.csdn.net/wx_assa/article/details/107878975
今日推荐