从n个无序的数中选出m个最大数

        “从n个无序的数中选出m个最大数”在刷阿里巴巴2017实习生笔试题时遇到的一道选择题,后来发现《剑指offer》面试题30也是讲述得这道题,看了相关的解法后总结如下:

       普通思路:将输入的n个无序的数进行排序,排序之后位于最前面的m个数即为所求。由于排序的时间复杂度最快为O(n*logn),因而这种思路的时间复杂度为O(n*logn)。

另外一个思路是:每次都扫描一遍这n个数,取出最大值,因而这样扫描m次就能得到最大的m个数。时间复杂度为O(m*n)。

改进思路1:如果基于第m个数来调整,使得比第m个数字小的所有数字都位于数组的左边,比第m个数字大的所有数字都位于数组的右边。这样调整之后,位数数组中左边的m个数字就是最小的m个数字(这k个数字不一定是排序的)。这种思路时间复杂度为O(n)。

参考代码如下:

void GetLeastNumbers_Solution1(int* input, int n, int* output, int k)
{
    if(input == NULL || output == NULL || k > n || n <= 0 || k <= 0)
        return;

    int start = 0;
    int end = n - 1;
    int index = Partition(input, n, start, end);
    while(index != k - 1)
    {
        if(index > k - 1)
        {
            end = index - 1;
            index = Partition(input, n, start, end);
        }
        else
        {
            start = index + 1;
            index = Partition(input, n, start, end);
        }
    }

    for(int i = 0; i < k; ++i)
        output[i] = input[i];
}

改进思路2:立一个m个数的有序集合(数组还是链表都可以)记录最小数,首先存入n个数中前m个元素,然后从n个数中第m+1个元素开始,逐个与该数组中的最小数进行比较,若大则进行替换。封装添加和删除操作,添加是进行排序,删除时选择最小数。这种思路时间复杂度为O(n*logm)。

参考代码如下:

typedef multiset<int, greater<int> >            intSet;
typedef multiset<int, greater<int> >::iterator  setIterator;

void GetLeastNumbers_Solution2(const vector<int>& data, intSet& leastNumbers, int k)
{
    leastNumbers.clear();

    if(k < 1 || data.size() < k)
        return;

    vector<int>::const_iterator iter = data.begin();
    for(; iter != data.end(); ++ iter)
    {
        if((leastNumbers.size()) < k)
            leastNumbers.insert(*iter);

        else
        {
            setIterator iterGreatest = leastNumbers.begin();

            if(*iter < *(leastNumbers.begin()))
            {
                leastNumbers.erase(iterGreatest);
                leastNumbers.insert(*iter);
            }
        }
    }
}

更多详细的分析可以看《剑指offer》这本书。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值