剑指offer(C++)--最小的K个数

题目

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

解法一

(平均时间复杂度为O(n)): 它会修改输入的数组
思想:基于partion函数来解决这个问题。如果基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字(这k个数字不一定是排序的)。

class Solution {
public:
//快速排序的partition函数
int partition(vector<int> &input, int low, int high)
{
    int pivotkey = input[low];
    while (low <high)
    {
        while (low < high && pivotkey <= input[high]) --high;
        input[low] = input[high];
        while (low < high && pivotkey >= input[low]) ++low;
        input[high] = input[low];
    }
    input[low] = pivotkey;
    return low;
}
    
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
      int n = input.size();
    if (0 == n || k >n || k<=0) return vector<int>();
    int low = 0;
    int high = n-1;
    int index = partition(input, low, high);
    //下标为index的不是第k小的数
    while (index +1 != k)
    {
        //第k个数在index的右边
        if (index+1 < k)
        {
            low = index+1;
            index = partition(input, low, high);
        }
        else
        {
            high = index - 1;
            index = partition(input, low, high);
        }
    }
     vector<int> res(input.begin(), input.begin() + k);
        return res;
    }
};

解法二

(时间复杂度为O(nlogk)):不必一次载入所有的数据到内存,适合从海量的数据中找出最小的k个数
思想:用multiset保存最小的k个数字。每次读入一个数,如果容器中已有的数字少于k个,则直接把这次读入的整数放入容器之中;如果容器中已有k个数字,则比较读入的数字和容器中最大的数字,如果前者大,则在容器中用前者替换后者;如果后者大,则前者不可能是最下的k个数之一

typedef multiset<int, greater<int>> intSet; //这里我们采用递减排序。默认的是less<key>,默认采用的是递增排序
typedef multiset<int, greater<int>>::iterator setIterator;

//在data中寻找最小的k个数保存到leastNumbers中
void getLeastNumbers(const vector<int> &data, intSet &leastNumbers, int k)
{
    leastNumbers.clear();
    if (k<1 || data.size() < k) 
        return;
    vector<int>::const_iterator it = data.begin();
    for (;it!=data.end();++it)
    {
        //如果leastNumbers中少于k个数
        if (leastNumbers.size() < k)
        {
            leastNumbers.insert(*it);
        }
        else
        {
            //如果该数比leastNumbers中最大的数小,则替换
            if (*it < *(leastNumbers.begin()))
            {
                leastNumbers.erase(leastNumbers.begin());
                leastNumbers.insert(*it);
            }
        }
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值