在《剑指offer》上看到的,而且Qunar去年的校招笔试也考了这题,今天晚上去西电腾讯的宣讲会,来宣讲的学长也说他当时一面的时候面试官问了“一亿个数据的最大的十个数”的面试题。今晚就写写最大 / 最小 的K个数的解题思路吧!
第一次见这个类型的题应该就是看Qunar的去年的校招笔试题,题目好像是一亿个数据,输出最大的100个数据。当时脑子里面的第一个想法就是维护一个100个数据的升序 / 降序数组,然后开始对数据开始一个一个的遍历,比较。然后就觉得自己好傻,那样肯定时间复杂度不行。后来看到的一种借助快速排序的划分的思想的解法和另一种借鉴堆排序的思想的解法。
类快速排序的解法就是选取一个数作为轴来划分数据,比它大的都放在右边,比它小的都放在左边,当这个数据的索引刚好是K的时候,则它前面的K个数刚好就是最小的数据。
时间复杂度为O(n),而且只有当我们可以修改数据位置的时候才能用。
代码如下
1 int partition(int *arr,int lo,int hi) 2 { 3 //随机化的快速排序,避免O(n^2) 4 swap(arr[lo],arr[lo+rand()%(hi-lo+1)]); 5 int pivot = arr[lo]; 6 while(lo<hi) 7 { 8 while(lo<hi && arr[hi]>=pivot) 9 --hi; 10 arr[lo] = arr[hi]; 11 12 while(lo<hi && arr[lo]<=pivot) 13 ++lo; 14 arr[hi] = arr[lo]; 15 } 16 arr[lo] = pivot; 17 return lo; 18 } 19 20 void GetMinKNumber(int *In,int n,int *Out,int k) 21 { 22 int start = 0; 23 int end = n; 24 int index = partition(In,0,n); 25 while(index!=k-1) 26 { 27 if (index > k-1) 28 { 29 end = index; 30 index = partition(In,start,end); 31 } 32 else 33 { 34 start = index; 35 index = partition(In,start,end); 36 } 37 } 38 for (int i=0;i<k;Out[i]=In[i],i++); 39 } 40 41 int main() 42 { 43 int arr[] = {3,4,6,-1,0}; 44 int n = sizeof(arr)/sizeof(int); 45 int *p = new int[3]; 46 GetMinKNumber(arr,n,p,3); 47 for (int i=0;i<3;i++) 48 { 49 cout<<p[i]<<endl; 50 } 51 return 0; 52 }
另一种借助堆排序的思想,时间复杂度为O(nlogk) ,不用改变数据位置,等我看完堆排序再来填坑。。。。。