【剑指offer】面试题40 最小的K个数

面试题–【剑指Offer】 题目解答

题目要求

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

题目分析

坑点:输入n个整数,找出其中最小的K个数
在这里我们很容易在主观上默认n>k,从而在讨论k的不合法性时,忘记了k>n的情况,实际上当 k>n 或者 k<=0 那么都将返回空!!!

下面我们从两种解法来讨论本题的做法

第一种,时间复杂O(n),对于一个排序的数组,我们只要输出他的前K个数字即可符合题意。

所以我们第一种做法是对数组进行排序,在这里可以有多种排序的方法,就不过多赘述了,不同的放法对应的效率不同。这里为了方便,我们使用stl里的排序函数进行排序。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> result;
        if(input.size() == 0 || k<=0 || k>input.size()) // 输入不合法的情况
            return result;
        sort(input.begin(),input.end());
        // k不合法 <0 ; k>size? 那么输出空
        for(int i=0;i<k;++i)
        {
            result.push_back(input[i]);
        }
        return result;
    }
};

第二种,我们用最大堆来实现,主要考虑在数据流较大时候的效率和可操作性。

思想是,我们先把数组中的前k个数保存起来,接下来只要依次比较后边的数,如果后面的数比k个数中最大的还大那么不予考虑,如果比最大的小那么就进行替换,所以我们还要知道k个书中最大的是那个,根据这个需要,我们需用从大到小排列顺序的multieset作为结构。k个数中的最大值就是multiset的首元素!

简化为为一个关系就是:插入—比较—替换(或不变)

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k)
    {
        vector<int> result;
        int len = input.size();
        if(input.empty() || k<=0 || len < k) return result;
         
        multiset<int, greater<int> > leastNumbers; // 从大到小排序
        multiset<int, greater<int> >::iterator iterGreater; // 定义迭代器
         
        vector<int>::iterator iter = input.begin();
        for(; iter != input.end(); ++iter)
        {
            // 将前k个数直接插入进multiset中,注意是小于K,取等号的话会多出一个数字
            if(leastNumbers.size() < k)
            {
                leastNumbers.insert(*iter);
            }
            else
            {
                // 因为设置的从大到小排序,故multiset中第一个位置的元素即为最大值
                iterGreater = leastNumbers.begin();
                 
                // 如果input中当前元素比multiset中最大元素小,则替换;即保持multiset中这k个元素是最小的。
                if(*iter < *(leastNumbers.begin()))
                {
                    // 替换掉当前最大值
                    leastNumbers.erase(iterGreater);
                    leastNumbers.insert(*iter);
                }
            }
        }
         
        for(iterGreater = leastNumbers.begin();iterGreater!=leastNumbers.end();++iterGreater)
        {
            result.push_back(*iterGreater); // 将multiset中这k个元素输出
        }
         
        return result;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值