百度笔试题-从20数组内取出最大的500个

来源:互联网 发布:wifi网络突然变得很差 编辑:程序博客网 时间:2024/05/17 23:28

题干

20个有序数组,每个数组有500个数字,取出这10000个数字中最大的500个,怎么做?

我的做法

(详见最后代码):

  1. 蛮力法:将这个10000个数组,放入一个数组内,然后排序,取出前500个。
  2. 写一个方法,将两个数组,将两个数组整合到一个数组里面,排序,前500个就是我们需要的,再反复调用这个方法。具体来说:有一个MAX先装满0,然后它先与A[1]装在一个1000的数组内后,排序,把前500个再复制给Max,然后再让MAX与A[2]重复上述过程,一直到A[19];

2个方法都很蠢。最好的做法:

见:http://zhidao.baidu.com/link?url=KU9AwrgsUsCXWMO7oOLTpt6WW58dHZRfQ36wyxsBYwdeSF07C-Pe6sjkrKwQnyGDoYUe_9QD9PKlu0bSGS9LPK

再用自己的话叙述一遍:

先作一个结构体:结构体内2个元素,一个是具体的数值,另一个是这个数值的来源。

然后从20个数组,分别取出最大的一个数,以结构体的形式,放入一个大小为20的数组。

对这个大小为20的数组进行排序(实际上这里如果使用最大堆的话,是不一定非要排序的,只需要完成建立最大堆的过程即可,当建立的完成最大堆后,最大元素就是需要被取走的元素,所以每次只需要调整一次堆即可,取出最大的一个数,放入大小为500的集合(这个集合装有最终的结果)。

从被取走的那个数的数值来源,再从那个数组取一个数,放入大小为20的数组。

重复上述过程。

最后集合内放有500个最大的数。


对于其中的排序,根据排序的时间复杂度,归并和堆排序都不错。

我自己手算试了一下,确实堆排序要更快一些。有时堆只有一步就可把最大值算出,归并要2步。

个人觉得这里用堆还是归并都不是重点了。

另外,需要记一下各类排序的时间复杂度和空间复杂度:

来自:http://en.wikipedia.org/wiki/Sorting_algorithm


上述标准答案的时间复杂度就是:519*log(2)20。我认为就是519乘以log以2为底的20.

因为,在最坏的情况下,每次要移动log(2)20个元素,从堆的最下面弄到最上面。一共要移动519次。当集合中有499个元素的时候,大小为20的数组必然要有20个,才能选出最后一个,所以一共进行了519次。


再看看我的2个算法的时间复杂度:

第一种:其实是看排序,我对一个n=10000的数组进行了排序,最好也是10000*log(2)10000,将20个数组的值赋值给10000的数组,我都不加了。

第二种:我对大小规模为1000的数组进行了排序10次,也就是10*1000*log(2)1000。比1还有点好一点


不过都没把握到解体的本质。


下面是我完成的源代码,标准答案主要在思路,我就没有写源码了。两种排序的输出结果一样的。

#include <stdlib.h>#include <stdio.h>#include <algorithm>int i,j,x;int A[20][500];int MAX[500];/*解法一,把这个20个数组放到一个数组内,再一降序排序,前500个就是最大的。这是个很没有水平的办法,要是让我找出10000000000000000000000个数的前5个,难道我还要遍历?但貌似不遍历也没有办法啊*/void solutionOne(){int a[10000];x=0;for(i=0;i<20;i++){for(j=0;j<500;j++){a[x]=A[i][j];x++;}}std::sort(a,a+10000);for(j=9999;j>9499;j--){printf("-%d-",a[j]);}}/*这个是qsort函数需要函数,用来区别升序还是降序,我们这里是降序*/int comp ( const void *a, const void *b ){    return *(int *)b-*(int *)a;//这样表示降序排列}void findMax500(int m){int temp[1000];x=0;for(j=0;j<500;j++){temp[x]=MAX[j];x++;}for(j=0;j<500;j++){temp[x]=A[m][j];x++;}qsort(temp,1000,sizeof(int),comp);for(j=0;j<500;j++){MAX[j]=temp[j];}}void main(){//创建数组并赋值for(i=0;i<20;i++){for(j=0;j<500;j++){A[i][j]=rand()%100000+1;}}//对每个数组排序,达到题目要求for(i=0;i<20;i++){std::sort(A[i],A[i]+500);}//打印其中某一个,看看是不是已经排好序了/*for(j=0;j<500;j++){printf("%d-",A[5][j]);}*//*现在已经完成了题设的要求*//*解法二:写一个方法,将两个数组,将两个数组整合到一个数组里面,排序,前500个就是我们需要的,再反复调用这个方法。有一个MAX先装满0,然后它先与A[1]装在一个1000的数组内后,排序,把前500个再复制给Max,然后再让MAX与A[2]重复上述过程,一直到A[19];*/for(j=0;j<500;j++){//初始化数组MAX,使其全为0MAX[j]=0;}for(i=0;i<20;i++){findMax500(i);}for(j=0;j<500;j++){printf("+%d+",MAX[j]);//打印出来后与solutionOne对比}solutionOne();system("pause");}