剑指offer 面试题40. 最小的k个数

O(N)划分法,注意这个方法会改变原数据(函数参数是引用的情况下)!当然也可以再定义一个新容器对其划分

要求前k小的数,只要执行快排划分,每次划分都会把数据分成大小两拨。直到某一次划分的中心点正好在k处,则左侧0~k-1的数字正好就是所求。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int n=input.size();
        if(n==0 or k==0 or n<k){return {};}
        int le=0,ri=n-1,mi;
        while((mi=partition(input,le,ri))!=k){//还没划分到k位置,接着划分
            if(mi>k){
                ri=mi-1;
            }
            else{
                le=mi+1;
            }
        }
        vector<int>res;
        for(int i=0;i<k;++i){
            res.push_back(input[i]);
        }
        return res;
    }
    //算法导论快排的划分算法
    int partition(vector<int>& nums,int le,int ri){
        if(le>=ri){return le;}
        int stable=nums[ri];
        int i=le-1,j=le;
        while(j<ri){
            if(nums[j]<stable){
                swap(nums[++i],nums[j]);
            }
            ++j;
        }
        swap(nums[i+1],nums[ri]);
        return i+1;
    }
};

O(N logK)堆排序法,这个方法特别适合海量数据,因为所有操作都在k大小的容器内进行!

要求最小的k个数,那么先在堆中放置k个数并建立最大堆,对于之后考察的每个数字x,如果x比堆里最大(也就是堆顶,因为是最大堆)更小,说明当前堆顶肯定不在最后的解中,所以把堆顶pop掉,并push当前x,再维护最大堆性质,接下来以此类推。最后剩下的堆就是所有数据里最小的k个。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int n=input.size();
        if(k==0 or n==0 or k>n){return {};}
        vector<int> heap(k,0);
        for(int i=0;i<k;++i){
            heap[i]=input[i];
        }
        make_heap(heap.begin(),heap.end());//默认就是大顶堆
        for(int i=k;i<n;++i){
            if(heap[0]>input[i]){
                pop_heap(heap.begin(),heap.end());
                heap.back()=input[i];
                push_heap(heap.begin(),heap.end());
            }
        }
        return heap;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值