面试题30:最小的K个数

来源:互联网 发布:淘宝上找不到的衣服 编辑:程序博客网 时间:2024/05/22 02:26

题目:输入n个整数,找出其中最小的k个数。

1)      On的时间复杂度,同样利用partition快排找到第k个数,然后比它小的都在左边,比他大的都在右边,输出K左边的数。

void GetLeastNumbers(int * numbers,int length,int k){if(numbers==NULL||length<=0||k>length||k<=0)return;int start=0;int end=length-1;int index=Partition(numbers,length,start,end);while(index!=k-1){if(index<k-1){start=index+1;index=Partition(numbers,length,start,end);}else{end=index-1;index=Partition(numbers,length,start,end);}}for(int i=0;i<k;i++){cout<<numbers[i]<<endl;}}

//快速排序中随机生成一个数字,将此大于此下标位置的数的元素放右边,小于的放左边int Partition(int * data,int length,int start,int end){if(data==NULL||length<=0||start<0||end>=length){throw new exception("invalid parameters");}//在起始位置和结束位置中随机生成一位数int index=randomInRange(start,end);//将index位置的数和最后一位交换,放置最后swap(&data[index],&data[end]);int small=start-1;//遍历数组for(index=start;index<end;index++){if(data[index]<data[end]){/*如果当前数小于分界元素,small++,和index相等,指向当前元素,向后遍历遇到大于分界元素的,small不变,直到遇到下一个小于分界元素的,对small再加1,此时small记录的就是第一个大于分界元素的元素下标,然后交换值*/small++;//如果small不指向当前位置if(index!=small){//交换当前元素和small位置的元素swap(&data[index],&data[small]);}}}++small;swap(&data[small],&data[end]);return small;//返回下标}//生成随机数int randomInRange(int start, int end)  {      srand(time(NULL));        return start + rand()%(end-start+1);  }//交换两个数的值void swap(int * a,int * b){int temp=*a;*a=*b;*b=temp;}




1)      O(nlogk)的时间复杂度,适合处理海量数据

我们可以先创建一个大小为K的数据容器来存储最小的K个数,接下来我们每次从输入的n个整数中读入一个数,如果容器中已有的数字少于K,则直接把这次读入的整数放入容器中;如果容器中已有K个数,就是容器满了,此时我们不能插入新的数字而只能替换已有的数字了。找出这K个数的最大值,然后拿这次待插入的整数和最大值相比较。如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还大,那么这个数不可能是最小的K个整数之一,于是我们可以抛弃这个数。我们可以用红黑树来实现这个数据容器,或者使用最大堆来实现,非常适合海量数据的处理。

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);            }        }    }}

java:

可以使用TreeSet,TreeSet中可以使元素按从小到大排序,遍历数组每次和最大的值比较。

public class TopK {public static void main(String[] args) {int[] array={0,5,2,7,9,11,12,4,3,6};PrintTopK(array,3);}public static void PrintTopK(int[] array,int k){if(array==null||k<1)return;TreeSet<Integer> ts=new TreeSet<Integer>();for(int i=0;i<array.length;i++){if(ts.size()<k){ts.add(array[i]);//如果容器中不够K个数,直接添加}else{if(array[i]<ts.last())//当前元素和ts最大值比(treeset中最后一个元素是最大值){ts.remove(ts.last());//移除treeset中的最大值ts.add(array[i]);//将当前元素插入}}}System.out.println(ts);}}



0 0
原创粉丝点击