答: 首先分析多大的内存能够表示10亿的数呢?一个int型占4字节,10亿就是40亿字节(很明显就是4GB),也就是如果完全读入内存需要占用4GB,而题目只给1GB内存,显然不可能将所有数据读入内存。
我们先不考虑时间复杂度,仅考虑解决问题。那么接下来的思路一般有两种。
- 位图法:用一个bit位来标识一个int整数。
- 分治法:分批处理这10亿的数。
一种是位图法,如果各位老司机有经验的话很快会想到int整型数是4字节(Byte),也就是32位(bit),如果能用一个bit位来标识一个int整数那么存储空间将大大减少。另一种是分治法,内存有限,我想办法分批读取处理。下面大致分析一下两种思路。
位图法(Bitmap)
位图法是基于int型数的表示范围这个概念的,用一个bit位来标识一个int整数,若该位为1,则说明该数出现;若该位为0,则说明该数没有出现。一个int整型数占4字节(Byte),也就是32位(bit)。那么把所有int整型数字表示出来需要2^32 bit的空间,换算成字节单位也就是2^32/8 = 2^29 Byte,大约等于512MB
这下就好办了,只需要用512MB的内存就能存储所有的int的范围数。
BitMap 表示
(1). 如何判断int数字放在哪一个tmp数组中:将数字直接除以32取整数部分(x/32),例如:整数8除以32取整等于0,那么8就在tmp[0]上;
(2). 如何确定数字放在32个位中的哪个位:将数字mod32取模(x%32)。上例中我们如何确定8在tmp[0]中的32个位中的哪个位,这种情况直接mod上32就ok,又如整数8,在tmp[0]中的第8 mod上32等于8,那么整数8就在tmp[0]中的第八个bit位(从右边数起)。
然后我们怎么统计只出现一次的数呢?每一个数出现的情况我们可以分为三种:0次、1次、大于1次。也就是说我们需要用2个bit位才能表示每个数的出现情况。此时则三种情况分别对应的bit位表示是:00、01、11
我们顺序扫描这10亿的数,在对应的双bit位上标记该数出现的次数。最后取出所有双bit位为01的int型数就可以了。
分治法
分治法目前看到的解决方案有哈希分桶(Hash Buckets)和归并排序两种方案。
哈希分桶的思想是先遍历一遍,按照hash分N桶(比如1000桶),映射到不同的文件中。这样平均每个文件就10MB,然后分别处理这1000个文件,找出没有重复的即可。一个相同的数字,绝对不会夸文件,有hash做保证。因为算法具体还不甚了解,这里先不做详细介绍。