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

这篇博客介绍了如何在输入的n个整数中找出最小的K个数。第一种方法利用multiset,每次比较并更新,时间复杂度为O(nlogK)。第二种方法基于快速排序的思想,时间复杂度为O(n),但会改变原始数组。对于大规模数据,基于multiset的方法更适用。

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

思路一:用一个multiset存储k个数,后面得到一个数,如果得到的数字比leastNumbers中的最大值大,则舍去,否则删掉最大值,插入得到的数到multiset中。直到所有的n-k数走一遍。则multiset中的k个数便是n个数中最小的k个数。

由于O(1)时间得到最大值,插入和删除的时间复杂度都是O(logK)时间。而需要n次操作,所以总的时间复杂度是O(nlogK)

typedef multiset<int,greater<int>> intSet;//greater<int>表示第一个元素(根)是最大的
typedef multiset<int,greater<int>>::iterator setIterator;
class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
          intSet leastNumbers;//leastNumbers用于存储k个元素
        vector<int> result;
          if(k < 1 || (input.size()) < (unsigned long)k)//判断输入是否有意义
              return result;
        vector<int>::const_iterator iter = input.begin();
        for(; iter != input.end(); iter++){
            if((leastNumbers.size()) < (unsigned long)k)//将前k个数插入leastNumbers中
                leastNumbers.insert(*iter);
            else{//将后面的进行比较,如果得到的数字比leastNumbers中的最大值大,则舍去,否则删掉最大值,插入得到的数字
                setIterator iterGreatest = leastNumbers.begin();
                if(*iter < *(leastNumbers.begin())){
                    leastNumbers.erase(iterGreatest);
                    leastNumbers.insert(*iter);
                }
            }
        }
        while(!leastNumbers.empty()){//将multiset中的数转存到vector中,时从大到小的排列
            setIterator iterGreatest = leastNumbers.begin();
            result.push_back(*iterGreatest);
            leastNumbers.erase(iterGreatest);
        }
        return result;
    }
};
思路二:利用快速排序算法给我们的启发,如果基于数组的第K个数字来调整,使得比K个数字小的所有数字都位于数组的左边,比第K个数字大的所有数字都位于数组的右边。

怎么实现呢?首先选择一个基准,实现基准左边的都小于等于基准,右边的都大于等于基准。再看基准是否在第k-1个位置,如果在k-1左边,则继续右边的操作,否则继续左边的操作。

由于次需要n次比较,但是只需要几次就可以了。时间复杂度是O(n)

但是不适合大规模的数字,因为内存不够。而且会改动输入数组。

这个代码就不写了。

两种思路的比较:

基于快速排序                                                                                     基于multiset

时间复杂度 O(n)                                                                                           O(nlogK)

是否需要修改输入数组                      是                                                                                                       否

是否适用于海量数据                           否                                                                                                      是


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值