【从零单排之微软面试100题系列】05之查找最小的k个元素

本题目选自July大神博客系列【微软面试100题】: july大神,该系列我主要用来记录我的学习笔记。

题目描述:输入n个整数,输出其中最小的k个(k<=n)

 

分析思路:(本题亦见于《剑指offer》面试题30)

最简单的思路莫过于先排序,然后输出排序后的前k个数。如果使用快排,时间复杂度是O(nlogn)

除此之外,还有其它解法。

解法1:基于数组的第k个数字来调整,使比第k个数字小的所有数字位于数组左边,比第k个数字大的所有数字位于数组右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字(但这k个数字不一定是排好序的)。这种方法的时间复杂度是O(n)

书中给的参考代码:

void GetLeastNumbers(int *input, int n, int* output, int k)
{
   if(input == NULL || n <= 0 || k > n || k <= 0)
      return;  
   int start = 0;
   int end = n - 1;
   int index = Partition(intput, 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];
}

//Partition的实现
int Partition(int* data, int nLength, int start, int end)
{
   if(data == NULL || nLength <= 0 || start < 0 || end > nLength - 1 || start > end)
         throw exception("Invalid Input!");
   int index = RandInRange(start,end);//随机生成start到end之间的整数
   Swap(&data[index], &data[end]);    //选择位置index上的值,并将其与end位置上的数交换
   
   int small = start - 1;             //small用来保存比选中的数小的数的位置
   for(index = start; index < end; ++index) 
   {
       if(data[index] < data[end])     
      {
          ++small;                    
          if(small != index)
               Swap(&data[index],&data[small]);  //如果data[index]<data[end],将small位置的数换成比选中的数小的data[index]
      }
   }
   ++small;
   Swap(&data[small], &data[end]);
   return small;
}

解法二:可以先创建一个大小为k的数据容器来存储最小的k个数字,接下来每次从n个数据中读取一个数。如果容器已有数字少于k个,则读取的数据可以直接放入容器之中;否则,找出已有k个数据中的最大数,与当前数据比较之后更新之。可以利用最大堆来实现该容器,因为最大堆的根结点总是最大,而完成删除和插入操作的时间复杂度是O(logk)。
在STL中,set和multiset都是基于红黑树实现的,于是可以利用STL的multiset容器,以下是参考代码:

typedef multiset<int, greater<int> >            intSet;
typedef multiset<int, greater<int> >::iterator  setIterator;
void GetLeastNunmbers(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)
            leasetNumbers.insert(*iter);
      else
      {
         setIterator iterGreatest = leastNumbers.begin();
         if(*iter < *iterGreatest)
         {
              leastNumbers.erase(iterGreatest);
              leastNumbers.insert(*iter);
         }
      }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值