关闭

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

标签: 微软面试题笔记
229人阅读 评论(0) 收藏 举报
分类:
本题目选自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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:3970次
    • 积分:223
    • 等级:
    • 排名:千里之外
    • 原创:20篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档
    最新评论