面试题30:最小的K个数
2015-06-01 20:32
671 查看
题目:输入n个整数,找出其中最小的k个数。
1) On的时间复杂度,同样利用partition快排找到第k个数,然后比它小的都在左边,比他大的都在右边,输出K左边的数。
1) O(nlogk)的时间复杂度,适合处理海量数据
我们可以先创建一个大小为K的数据容器来存储最小的K个数,接下来我们每次从输入的n个整数中读入一个数,如果容器中已有的数字少于K,则直接把这次读入的整数放入容器中;如果容器中已有K个数,就是容器满了,此时我们不能插入新的数字而只能替换已有的数字了。找出这K个数的最大值,然后拿这次待插入的整数和最大值相比较。如果待插入的值比当前已有的最大值小,则用这个数替换当前已有的最大值;如果待插入的值比当前已有的最大值还大,那么这个数不可能是最小的K个整数之一,于是我们可以抛弃这个数。我们可以用红黑树来实现这个数据容器,或者使用最大堆来实现,非常适合海量数据的处理。
java:
可以使用TreeSet,TreeSet中可以使元素按从小到大排序,遍历数组每次和最大的值比较。
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); } }
相关文章推荐
- 面试题29:数组中出现次数超过一半的数字
- 黑马程序员——java基础----集合框架知识点总结(一)
- 黑马程序员_java语言_StringBuffer,Array以及Integer分析
- java求职宝典
- 黑马程序员--Java基础Day01
- 黑马程序员——银行业务调度系统
- 黑马程序员——交通灯管理系统
- 黑马程序员——反射
- 黑马程序员——IO流(三)
- 《经验分享收集》 一:10+年程序员总结的20+条经验教训
- Java面试题-并发工具
- Java面试题-Java中的锁
- Java面试题-并发容器和框架
- Java面试题-线程安全
- Java面试题-并发框架
- Java面试题-锁
- Java面试题-多线程
- 面试题28:求字符的全排列
- 面试题27:二叉搜索树转换为有序双向链表
- 黑马程序员——Java基础—String类