选一个数t,通过让这个数和其它数比较,我们可以将整个数组分成了两部分并且满足,{x,xx,…,t}<{y,yy,…}。 在将数组分成两个数组的过程中,我们还可以记录每个子数组的大小。这样我们就可以确定第k大的数字在哪个子数组中。 然后我们继续对包含第k大数字的子数组进行同样的划分,直到找到第k大的数字为止。 平均来说,由于每次划分都会使子数组缩小到原来1/2,所以整个过程的复杂度为O(N)。 17、给40亿个不重复的unsigned int的整数,没排过序的,然后再给几个数,如何快速判断这几个数是否在那40亿个数当中 答案: unsigned int的取值范围是0到2^32-1。我们可以申请连续的2^32/8=512M的内存,用每一个bit对应一个unsigned int数字。首先将512M内存都初始化为0,然后每处理一个数字就将其对应的bit设置为1。当需要查询时,直接找到对应bit,看其值是0还是1即可。 18、在一个文件中有10G个整数,乱序排列,要求找出中位数。内存限制为2G。 回答: 不妨假设10G个整数是64bit的。 2G内存可以存放256M个64bit整数。 我们可以将64bit的整数空间平均分成256M个取值范围,用2G的内存对每个取值范围内出现整数个数进行统计。这样遍历一边10G整数后,我们便知道中数在那个范围内出现,以及这个范围内总共出现了多少个整数。 如果中数所在范围出现的整数比较少,我们就可以对这个范围内的整数进行排序,找到中数。如果这个范围内出现的整数比较多,我们还可以采用同样的方法将此范围再次分成多个更小的范围(256M=2^28,所以最多需要3次就可以将此范围缩小到1,也就找到了中数)。 19、时分秒针在一天之内重合多少次?(24小时) 2次 而时针和分针重合了22次。 20、将多个集合合并成没有交集的集合。 给定一个字符串的集合,格式如:{aaabbbccc},{bbbddd},{eeefff},{ggg},{dddhhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaabbbcccdddhhh},{eeefff},{ggg}。 (1)请描述你解决这个问题的思路; (2)请给出主要的处理流程,算法,以及算法的复杂度 (3)请描述可能的改进。 回答: 集合使用hash_set来表示,这样合并时间复杂度比较低。 1、给每个集合编号为0,1,2,3… 2、创建一个hash_map,key为字符串,value为一个链表,链表节点为字符串所在集合的编号。遍历所有的集合,将字符串和对应的集合编号插入到hash_map中去。 3、创建一个长度等于集合个数的int数组,表示集合间的合并关系。例如,下标为5的元素值为3,表示将下标为5的集合合并到下标为3的集合中去。开始时将所有值都初始化为-1,表示集合间没有互相合并。在集合合并的过程中,我们将所有的字符串都合并到编号较小的集合中去。 遍历第二步中生成的hash_map,对于每个value中的链表,首先找到最小的集合编号(有些集合已经被合并过,需要顺着合并关系数组找到合并后的集合编号),然后将链表中所有编号的集合都合并到编号最小的集合中(通过更改合并关系数组)。 4、现在合并关系数组中值为-1的集合即为最终的集合,它的元素来源于所有直接或间接指向它的集合。 算法的复杂度为O(n),其中n为所有集合中的元素个数。 题目中的例子: 0:{aaabbbccc} 1:{bbbddd} 2:{eeefff} 3:{ggg} 4:{dddhhh} 生成的hash_map,和处理完每个值后的合并关系数组分别为 aaa:0。[-1,-1,-1,-1,-1] bbb:0,1。[-1,0,-1,-1,-1] ccc:0。[-1,0,-1,-1,-1] ddd:1,4。[-1,0,-1,-1,0] eee:2。[-1,0,-1,-1,0] fff:2。[-1,0,-1,-1,0] ggg:3。[-1,0,-1,-1,0] hhh:4。[-1,0,-1,-1,0] 所以合并完后有三个集合,第0,1,4个集合合并到了一起。
|