TOP-K问题

常见的Top k问题,下面以多种解法来解决这个问题
下面拿一道Leetcode上的题目来练练手。
面试题40. 最小的k个数
题意:返回最小的k个数

快速排序

其实最简单的思路是排一下序,然后把前k个返回

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        sort(arr.begin(),arr.end());
        vector<int> res;
        for(int i=0;i<k;i++) res.push_back(arr[i]);
        return res;
    }
};

平均时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度 O(k)

大根堆

维护一个大小为k的大根堆,根的首部元素是最大的,先把前k个插入,然后将剩下的元素逐个与堆的顶部元素比较,如果小于的话,就弹出顶部元素,插入该元素,最后将堆的全部元素弹出到数组返回。

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int> res;
        if(k==0) return res;
        priority_queue<int,vector<int>,less<int>> heap;
        for(int i=0;i<k;i++){
            heap.push(arr[i]);
        }
        for(int i=k;i<arr.size();i++){
            if(arr[i]<heap.top()){
                heap.pop();
                heap.push(arr[i]);
            }
        }
        while(heap.size()){
            res.push_back(heap.top());
            heap.pop();
        }
        return res; 
    }
};

其实一开始我用mutiset实现了一个大根堆,效果是一样的。

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        multiset<int> s;
        vector<int> res;
        if(k==0) return res;
        int i;
        for(i=0;i<k;i++){
            s.insert(arr[i]);
        }
        for(;i<arr.size();i++){
            set<int>::iterator it = s.end();
            it--;
            if(arr[i]<*it){
                s.erase(it);
                s.insert(arr[i]);
            }
        }
        set<int>::iterator it = s.begin();
        for(;it!=s.end();it++){
            res.push_back(*it);
        }
        return res;
    }
};

堆的插入和删除都是 O ( l o g n ) O(logn) O(logn),所以最坏时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),空间复杂度是 O ( k ) O(k) O(k)

nth_element

nth_element(arr.begin(),arr.begin()+k,arr.end())
用来求第k+1小的元素,也就是arr[k]归位,比arr[k]小的都在其左边,比它大的都在它右边,但不保证有序,平均时间复杂度 O ( n ) O(n) O(n)

class Solution {
public:
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        nth_element(arr.begin(),arr.begin()+k,arr.end());
        arr.resize(k);
        return arr;
    }
};

partition

采用快排一次划分的思想,并加入随机化,平均复杂度为 O ( n ) O(n) O(n)

参考:最小的k个数

typedef unsigned long long ull;
class Solution {
public:
    int partition(vector<int>& arr, int low, int high){
        int pivot = arr[low];
        while(low<high){
            while(low<high&&arr[high]>=pivot) --high;
            arr[low] = arr[high];
            while(low<high&&arr[low]<pivot) ++low;
            arr[high] = arr[low];
        }
        arr[low] = pivot;
        return low;
    }
    int randomized_partition(vector<int>& arr,int low,int high){
        int index = rand()%(high-low+1)+low;
        swap(arr[index],arr[low]);
        return partition(arr,low,high);
    }
    void randomized_select(vector<int>& arr,int low,int high,int k){
        if(low>high) return ;
        int pos = randomized_partition(arr,low,high);
        if(pos-low+1==k) return ;
        else if(pos-low+1>k) randomized_select(arr,low,pos-1,k);
        else randomized_select(arr,pos+1,high,k-(pos-low+1));
    }
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        srand(unsigned(time(NULL)));
        randomized_select(arr,0,arr.size()-1,k);
        arr.resize(k);
        return arr;
    }
};

BFPRT

O(n)的算法求topk,待补。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值