文件中有40亿个QQ号码,请设计算法对QQ号码去重,相同的QQ号码仅保留一个,内存限制1G.

20211210101625294

在原题中,实际有40亿个QQ号码,为了方便起见,在图解和叙述时,仅以4个QQ为例来说明。

方法一:排序

很自然地,最简单的方式是对所有的QQ号码进行排序,重复的QQ号码必然相邻,保留第一个,去掉后面重复的就行。

原始的QQ号为:

20211210101625310

排序后的QQ号为:

20211210101625326

去重就简单了:

20211210101625342

可是,去重一定要排序吗?显然,排序的时间复杂度太高了。

方法二:hashmap

既然直接排序的时间复杂度太高,那就用hashmap吧,具体思路是把QQ号码记录到hashmap中:

1
2
3
4
mapFlag[123] = true
mapFlag[567] = true
mapFlag[123] = true
mapFlag[890] = true

由于hashmap的去重性质,可知实际自动变成了:

1
2
3
mapFlag[123] = true
mapFlag[567] = true
mapFlag[890] = true

很显然,只有123,567,890存在,所以这也就是去重后的结果。

可是,实际要存40亿QQ号码,1G的内存够分配这么多空间吗?显然不行。

方法三:文件切割

显然,这是海量数据问题。看过很多面经的求职者,自然想到文件切割的方式,避免内存过大。

可是,绞尽脑汁思考,要么使用文件间的归并排序,要么使用桶排序,反正最终是能排序的。

既然排序好了,那就能实现去重了,貌似就万事大吉了。可是,这么多的文件操作,效率自然不高啊。显然,无法通过。

方法四:bitmap

来看绝招!我们可以对hashmap进行优化,采用bitmap这种数据结构,可以顺利地同时解决时间问题和空间问题。

在很多实际项目中,bitmap经常用到。我看了不少组件的源码,发现很多地方都有bitmap实现,bitmap图解如下:

20211210101625358

这是一个unsigned char类型,可以看到,共有8位,取值范围是[0, 255],如上这个unsigned char的值是255,它能标识0~7这些数字都存在。

同理,如下这个unsigned char类型的值是254,它对应的含义是:1~7这些数字存在,而数字0不存在:

20211210101625373

由此可见,一个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数组来记录文件中QQ号码的存在与否,形成一个bitmap,比如:

1
2
3
4
bitmapFlag[123] = 1
bitmapFlag[567] = 1
bitmapFlag[123] = 1
bitmapFlag[890] = 1

实际上就是:

1
2
3
bitmapFlag[123] = 1
bitmapFlag[567] = 1
bitmapFlag[890] = 1

然后从小到大遍历所有正整数(4字节),当bitmapFlag值为1时,就表明该数是存在的。

而且,从上面的过程可以看到,自动实现了去重。显然,这种方式可以。

转载—原文地址

�文地址](https://mp.weixin.qq.com/s/VBiBz8JuqhWu9wcN1JBqsQ)

)