剑指offer:29.最小的K个数

29.最小的K个数

题目描述

  • 输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,

 

解题思路

下面的思路来自《剑指offer》

  • 思路一,快速排序后取前k位,写个快速排序还不是分分钟的事?看一下代码会发现实际上并不需要完全排序完毕。这种方法比较快,但是会对输入数组进行修改,如果要求不能修改输入数组的话这种方法就不好用了。

  • 思路二,用一个大小为k的容器(最大堆或者红黑树),依次读取数据,如果比当前容器最大值小的话,就用这个数替换容器的最大值,并重新计算最大值,否则放弃这个数。最后容器内的k个数就是最小的k个数。这个容器可以用STL中的最大堆(根结点的值总是大于其子树中任意结点的值)或者红黑树来实现。这种方法可以不用修改输入数组,适用于海量数据。

    STL中关于堆的操作:

    头文件是#include <algorithm>,牛客网的编辑器好像已经包含了该头文件。

    (1)make_heap()构造堆

    void make_heap(first_pointer,end_pointer,compare_function);

    默认比较函数是(<),即最大堆。

    函数的作用是将[begin,end)内的元素处理成堆的结构,此时下标为0的位置为最大值

    (2)push_heap()添加元素到堆

    void push_heap(first_pointer,end_pointer,compare_function);

    新添加一个元素在末尾,然后重新调整堆序。该算法必须是在一个已经满足堆序的条件下。

    先在vector的末尾添加元素,再调用push_heap

    (3)pop_heap()从堆中移出元素

    void pop_heap(first_pointer,end_pointer,compare_function);

    把堆顶元素取出来,放到了数组或者是vector的末尾。

    要取走,则可以使用底部容器(vector)提供的pop_back()函数。

    先调用pop_heap再从vectorpop_back元素

    (4)sort_heap()对整个堆排序

    void sort_heap (first_pointer,end_pointer,compare_function);

    排序之后的元素就不再是一个合法的堆了,就变成从小到大排序了,和sort函数的效果一样。

 

代码

  • 思路一,快速排序法
class Solution {
private:
    int Partition(vector<int> &input, int left, int right){
        int pivot = input[left];
        while(left<right){
            while(right>left && input[right]>=pivot){
                right--;
            }
            input[left] = input[right];
            while(left<right && input[left]<=pivot){
                left++;
            }
            input[right] = input[left];
        }
        input[left] = pivot;
        return left;
    }
    
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int length = input.size();
        if(length==0 || k<=0 || k>length) return vector<int>();
        
        int left = 0;
        int right = length-1;
        int index = Partition(input, left, right);
        while(index!=k-1){
            if(index<k-1){
                left = index+1;
            }
            else{
                right = index-1;
            }
            index = Partition(input, left, right);
        }
        
        vector<int> result(input.begin(), input.begin()+k);
        return result;
    }
};
  • 思路二,最大堆(如果比较强的话可以自己写堆相关的代码)
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        int length = input.size();
        if(length==0 || k<=0 || k>length) return vector<int>();
        
        // 通过数组地址初始化vector数组
        vector<int> result(input.begin(), input.begin()+k);
        // 构造大顶堆,最后一个参数默认就是less<int>(),即大顶堆,因此可以不写
        make_heap(result.begin(), result.end(), less<int>());
        
        for(int i=k; i<length; i++){
            if(input[i]<result[0]){
                pop_heap(result.begin(), result.end(), less<int>());
                result.pop_back();
                result.push_back(input[i]);
                push_heap(result.begin(), result.end(), less<int>());
            }
        }
        sort_heap(result.begin(), result.end(), less<int>());
        return result;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值