JZ40 最小的K个数

最小的K个数_牛客题霸_牛客网

描述

给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。

数据范围:0≤k,n≤100000≤k,n≤10000,数组中每个数的大小0≤val≤10000≤val≤1000

要求:空间复杂度 O(n)O(n) ,时间复杂度 O(nlogk)O(nlogk)

示例1

输入:[4,5,1,6,2,7,3,8],4        返回值:[1,2,3,4]

说明:返回最小的4个数即可,返回[1,3,2,4]也可以

解法:

1.分治:快排思想,比较K和分治后pos的大小,如果相等,说明找到了,pos前面的数就是结果.,题目要求还需要对pos前的元素进行排序。

2.维护一个K个节点的大根堆,对于[k,n-1]之间的元素,每次拿堆顶元素和当前元素对比,交

换比堆顶元素小的,重新调整。

3.书中解题,多重哈希表,哈希表从大到小排序,依次往哈希表插入k个元素,如果哈希表有了k个元素,往后每遍历一个值,把0号元素(最大值)和当前元素进行对比,0号元素比进来的元素小,删除0号元素,插入当前元素。

1.分治

#include <any>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param input int整型vector 
     * @param k int整型 
     * @return int整型vector
     */
    // 分治
     int partition(vector<int>& input, int left, int right, int k ){
        int i = left, j = left;
        for(; i < right; ++i){
            if(input[i] < input[right]){
                swap(input[i], input[j]);
                ++j;
            }
        }
        swap(input[j],input[right]);

        if(j == k - 1) return j;
        else if(j > k - 1) return partition(input, left, j-1, k);
        else if(j < k - 1) return partition(input, j+1, right, k);
        return -1;
     }
    vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
        // write code here
        if(!k || input.empty()) return vector<int>{};
        
        vector<int> res;
        // 1.分治
        int res_pos = partition(input, 0, input.size() - 1, k);
        copy_n(input.begin(), k,back_inserter(res));
        return res;
    }


};

2.K个节点的大根堆

#include <any>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param input int整型vector 
     * @param k int整型 
     * @return int整型vector
     */
    
    vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
        // write code here
        if(!k || input.empty()) return vector<int>{};
        
        vector<int> res;

        // 2.K个结点的大根堆
        int nums_size = input.size();
        for(int idx = k / 2 - 1; idx >=0 ; --idx){
            adjustMaxHeap(input, idx, k);
        } //维护K个结点的大根堆

        for(int idx = k; idx < nums_size; ++idx){
            if(input[0] > input[idx]){ //把K后面的值依次和堆顶比较, 如果堆顶元素>新插入的元素
                swap(input[0], input[idx]);
                adjustMaxHeap(input, 0, k); //调整为大根堆
            }
        }
        copy_n(input.begin(), k, back_inserter(res));
        sort(res.begin(), res.end()); 
        return res;
        
    }

    //维护一个k个结点的大根堆
    void adjustMaxHeap(vector<int>&input, int pos, int len){
        int dad = pos;
        int son =  2*dad +1;
        while(son < len){
            if(son +1 < len && input[son] < input[son+1]){
                ++son;
            }
            if(input[son] > input[dad] ){
                swap(input[son],input[dad]);
                dad = son;
                son = 2 * dad + 1;
            }
            else break;
        }
    }

};

3.multi_set

#include <any>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param input int整型vector 
     * @param k int整型 
     * @return int整型vector
     */
    vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
        // write code here
        if(!k || input.empty()) return vector<int>{};
        
        vector<int> res;
        
        //书中解题3,多重哈希表,哈希表从大到小排序,依次往哈希表插入k个元素,
        //如果哈希表有了k个元素,往后每遍历一个值,把0号元素和当前元素进行对比,0号元素比进来的元素小,删除0号元素,插入当前元素。
        multiset<int, greater<int>> hash_table;
        for(int idx = 0; idx < input.size(); ++idx){
            if(hash_table.size() < k){ 
                hash_table.insert(input[idx]);
            }
            else{
                if(*hash_table.begin() > input[idx]){
                    hash_table.erase(hash_table.begin());
                    hash_table.insert(input[idx]);
                }
            }
        }
        // //从小到大插入结果容器vector
        copy(hash_table.rbegin(),hash_table.rend(), back_inserter(res));
        return res;
    }

   

};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

给你。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值