腾讯终面:求两个文件中的QQ交集
The following article is from 爱码有道 Author 点击关注👉👉
如若转载请联系原公众号
今天,我们来看一道腾讯的终面题目,能否做对这道题,在很大程度上决定了能否拿到腾讯的offer,来看看:
A文件有30亿个QQ号码,B文件有40亿个QQ号码,求A文件和B文件中QQ号码的交集,内存大小限制为1GB.
一. 直接暴力比较
最简单的方法是直接暴力比较,如下:
显然,这种方法要比较的次数是:30亿*40亿,时间复杂度太大了,无法通过腾讯面试。
二. 利用hashmap
既然时间复杂度不符合要求,那就要反思一下暴力比较的算法了,显然,应该用哈希表,优化查找速度,如下:
显然,时间复杂度大大降低,只需要遍历上面一层即可。然而,空间的占用还是太大了,1GB的内存根本无法容纳40亿个QQ号。
三. 分治切割文件
既然内存容纳不下,那就想办法进行切割吧,比如:根据QQ号码的最后一位的值来切割A文件和B文件,使文件变小。显然,尾数为j的QQ号码只可能在Aj文件和Bj文件中,只需要比较Aj和Bj文件即可。
QQ号最后一位 | A文件的切割 | B文件的切割 |
0 | A0 | B0 |
1 | A1 | B1 |
2 | A2 | B2 |
3 | A3 | B3 |
... | ... | ... |
通过切割的方法,可以化大为小,让内存容纳得下,对应的图示如下:
需要强调的是,仅仅以QQ号最后一位来划分,那么每个小文件的数据量大约是原来文件的1/10, 可能还是偏大,怎么办?
可以考虑以QQ号的最后3位来划分,那么每个小文件的数据量大约是原来大文件的1/1000,甚至还可以更细地来进行划分。
通过一定的规则进行分割,把A文件和B文件中同类型数据划分到对应的小文件中,解决了内存问题,能勉强通过腾讯面试。
四. 利用bitmap
我们回头看一下,要么是时间不符合要求,要么是空间不符合要求,那有没有时间和空间都符合要求的数据结构呢?
显然有的!我们可以对hashmap进行优化,采用bitmap这种数据结构,可以顺利地同时解决时间问题和空间问题。
在很多实际项目中,bitmap经常用到。我看了不少组件的源码,发现很多地方都有bitmap实现,bitmap图解如下:
这是一个unsigned char类型,可以看到,共有8位,取值范围是[0, 255],如上这个unsigned char的值是255,它能标识0~7这些数字都存在。
同理,如下这个unsigned char类型的值是254,它对应的含义是:1~7这些数字存在,而数字0不存在:
由此可见,一个unsigned char类型的数据,可以标识0~7这8个整数的存在与否。以此类推:
一个unsigned int类型数据可以标识0~31这32个整数的存在与否。
两个unsigned int类型数据可以标识0~63这64个整数的存在与否。
显然,可以推导出来:512MB大小足够标识所有QQ号码的存在与否,请注意:QQ号码的理论最大值为2^32 - 1,大概是43亿左右。接下来的问题就很简单了:
用512MB的unsigned int数组来记录B文件中QQ号码的存在与否,形成一个bitmap. 然后遍历A文件中的QQ, 看是否在bitmap中,如果在,那么该QQ号码就同时存在于A和B两个文件中。
bitmap非常巧妙,这种方式能通过腾讯的面试。当时我在腾讯终面时时遇到了这个题目,先简要指明了为什么1和2方法不行,然后给出了3和4中的方法,并说明了3和4的优缺点,万事大吉。
推荐阅读:
每日打卡赢积分兑换书籍入口