名企笔试:2015阿里面试题(相同数字问题)

1、题目要求

 

有A、B两个文件,文件格式相同,均为每行一个十进制整型数字,两个文件的行数不一定相等但均在一千万行左右。A文件中的数字两两不等,B文件中的数字两两不等,请用一个算法找出A和B两文件中所有相同的数,并且从小到大有序输出


2、程序分析

 

2.1 bitmap

这种问题,如果使用集合,则是非常容易的,但既是一个算法题目,自然不能如此简单,通常,考察算法时,一般来说,除了数组外,其他诸如字典,集合就不要使用了

考察算法时,重点是考察时间复杂度和空间复杂度,一千万int整数,大于38M,两个文件加一起是76M,如果用bitmap来存储,则是2M多一点

一个int类型的数值,有4个字节,32位,就可以表示32个数字的存在与否,比如8,就可以标识为3是存在的,因为8 = 1<<3

使用这种方法,程序只需要很小的空间,就可以表示许多数的存在情况,假设数据范围是1到100,那么只需要一个list,list里有4个int类型的数值,每个数值表示32个数值存在与否的情况

具体到本题,还不能用一个int类型数值来表示32个数存在与否的情况,而是要用一个int类型的数值表示16个数字存在与否的情况

2.2 解题思路

为了分析方便,我把题目简化,两个文件里的数值范围是1~100

1、令lst = [0,0,0,0,0,0,0]

2、从A文件中读出一个3,则3 / 16 = 0,3这个数值存在与否的情况用lst[0]来表示

3、3 % 16 = 3 ,3 * 2  = 6,将lst[0] 的二进制中的第6位设置为1 ,lst[0] = lst[0] & (1<<6),这里说的第6个bit位是从0开始计数的

4、A文件里的其他数值也这样做处理,A文件读取结束后,再读取B文件

5、如果从B文件里读取到了一个数值3,这应该清楚,判断A文件里是不是也有3,就看lst[0]的二进制的第6位是否为0,如果为0,则将第7个bit位也设置为0,这样,就表明,B文件里也有3

6、两份文件都去以后,从1遍历到100,当遍历到3时,则查看lst[0]的第7个bit位是否为1,如果是,则输出3


 

3、 示例代码

 

#coding=utf-8
'''
有A、B两个文件,文件格式相同,均为每行一个十进制整型数字,两个文件的行数不一定相等,
但均在一千万行左右。A文件中的数字两两不等,B文件中的数字两两不等,
请用一个算法找出A和B两文件中所有相同的数,并且从小到大有序输出
'''
import random

#获得一个随机序列,最大值为max,共count个元素
def get_random_lst(max,count):
    lst = []
    while len(lst) < count:
        r_int = random.randint(1,max)
        if not r_int in lst:
            lst.append(r_int)
    return lst

left_lst = get_random_lst(100,50)
right_lst = get_random_lst(100,50)

print set(left_lst).intersection(set(right_lst))

store_lst = [0,0,0,0,0,0,0]
for item in left_lst:
    lst_index = item / 16
    bit_index = (item % 16)*2
    store_lst[lst_index] = store_lst[lst_index] | (1 << bit_index)

for item in right_lst:
    lst_index = item / 16
    bit_index = (item % 16)*2
    exist = (store_lst[lst_index] >> bit_index) & 1
    if exist:
        store_lst[lst_index] = store_lst[lst_index] | (1 << (item % 16)*2 + 1)


for item in range(101):
    lst_index = item / 16
    bit_index = (item % 16)*2 + 1
    exist = (store_lst[lst_index] >> bit_index) & 1
    if exist:
        print item