40亿个非负整数中找到没出现的数
2015-09-29 16:55
281 查看
40亿个非负整数中找到没出现的数
【题目】
32位无符号整数的范围是0 - 4294967295,现在有一个正好包含40亿个无符号整数的文件,所以在整个范围中必然有没出现过的数。可以使用最多1GB的内存,怎么找到所有没出现过的数?
【解答】
对于原问题,如果使用哈希表来保存出现过的数,那么最坏情况下是40亿个数都不相同,那么哈希表则需要保存40亿条数据,一个32位整数需要4B,那么40亿*4B = 160亿个字节,一般大概10个字节的数据需要1G的空间,那么大概需要16G的空间,这不符合要求。
我们换一种方式,申请一个bit数组,数组大小为4294967295,大概为40亿bit,40亿/8 = 5亿字节,那么需要0.5G空间, bit数组的每个位置有两种状态0和1,那么怎么使用这个bit数组呢?呵呵,数组的长度刚好满足我们整数的个数范围,那么数组的每个下标值对应4294967295中的一个数,逐个遍历40亿个无符号数,例如,遇到100,则
bitArray[100] = 1,遇到9999,则bitArray[9999] = 1,遍历完所有的数,将数组相应位置变为1。
【进阶】
如果将上题的内存空间限制改为10MB,但是只用找到一个没出现过的数即可。
【解答】
本题将内存空间缩小为10MB,对于40亿个数据来说那是明显不够用的,那么我们只有将数据分块处理,分块应该怎么分,分多少块合理呢?根据我做过的题经验来看,10亿个字节的数据大概需要1GB空间处理(如果这个结论不正确欢迎读者指出),那么10MB内存换算过来就是可以处理1千万字节的数据,也就是8千万bit,对于40亿非负整数如果申请bit数组的话,40亿bit
/ 0.8亿bit = 50,那么这样最少也得分50块来处理,处理每块数据的时候几乎用完了内存空间,这样也不太好。看书上解说是分成了64块,至于为什么是64我目前也不是很了解,我只知道最少50块。所以下面就以64块来进行分析解答吧。
首先,将0 - 4294967259这个范围平均分成64个区间,每个区间是67108864个数,为了定位更加准确一些,我们先开辟一个大小为64的整型数组intArray,将40亿个数进行区间划分,第0区间(0-67108863)、第一区间(67108864-134217728)、第i区间(67108864*i-67108864*(i+1)-1),......,第63区间(4227858432
- 4294967259)。intArray分别记录每个区间出现的数的个数,肯定至少有一个区间上的计数少于67108864.利用这一点可以快速找出一个没有出现过的数。
第一遍遍历40亿个数过程如下:
1、申请长度为64的整型数组intArray[64],占用内存空间为64*4B;
2、遍历40亿个数,如果当前数为num,则num / 67108864 = i,那么intArray[i]++;
3、然后遍历intArray数组,找出一个计数小于67108864的位置k。
找出位于某个区间 k 的所有数之后,再从中找出一个没有出现过的数,则问题就解决了。申请一个长度为67108864的bit数组,数组每个位置有两个状态 0和1,如果第 k区间出现的数就赋值为1,没有出现就是0,最后遍历一下bitArray,就可以找到状态是0的一个数,就是没有出现过的那个数。
第二遍遍历40亿个数过程如下:
1、申请长度为67108864的bit数组bitArray[67108864],占用内存空间大约8MB;
2、再遍历40亿个数,这次只需要找出位于区间 k 的所有数,如果 n / 67108864 == k,那么n属于k区间;
3、在第2步的找出的 n,将bitArray[n - 67108864*k]的值置为 1,只做第k区间上数的bitArray映射;
4、遍历完成之后,在bitArray上必然存在状态是0的位置,假设第 i 个位置没被设置成1,那么67108864*k + i这个数就是有个没有出现过的数。
如此两遍遍历问题就得到解决。
【题目】
32位无符号整数的范围是0 - 4294967295,现在有一个正好包含40亿个无符号整数的文件,所以在整个范围中必然有没出现过的数。可以使用最多1GB的内存,怎么找到所有没出现过的数?
【解答】
对于原问题,如果使用哈希表来保存出现过的数,那么最坏情况下是40亿个数都不相同,那么哈希表则需要保存40亿条数据,一个32位整数需要4B,那么40亿*4B = 160亿个字节,一般大概10个字节的数据需要1G的空间,那么大概需要16G的空间,这不符合要求。
我们换一种方式,申请一个bit数组,数组大小为4294967295,大概为40亿bit,40亿/8 = 5亿字节,那么需要0.5G空间, bit数组的每个位置有两种状态0和1,那么怎么使用这个bit数组呢?呵呵,数组的长度刚好满足我们整数的个数范围,那么数组的每个下标值对应4294967295中的一个数,逐个遍历40亿个无符号数,例如,遇到100,则
bitArray[100] = 1,遇到9999,则bitArray[9999] = 1,遍历完所有的数,将数组相应位置变为1。
【进阶】
如果将上题的内存空间限制改为10MB,但是只用找到一个没出现过的数即可。
【解答】
本题将内存空间缩小为10MB,对于40亿个数据来说那是明显不够用的,那么我们只有将数据分块处理,分块应该怎么分,分多少块合理呢?根据我做过的题经验来看,10亿个字节的数据大概需要1GB空间处理(如果这个结论不正确欢迎读者指出),那么10MB内存换算过来就是可以处理1千万字节的数据,也就是8千万bit,对于40亿非负整数如果申请bit数组的话,40亿bit
/ 0.8亿bit = 50,那么这样最少也得分50块来处理,处理每块数据的时候几乎用完了内存空间,这样也不太好。看书上解说是分成了64块,至于为什么是64我目前也不是很了解,我只知道最少50块。所以下面就以64块来进行分析解答吧。
首先,将0 - 4294967259这个范围平均分成64个区间,每个区间是67108864个数,为了定位更加准确一些,我们先开辟一个大小为64的整型数组intArray,将40亿个数进行区间划分,第0区间(0-67108863)、第一区间(67108864-134217728)、第i区间(67108864*i-67108864*(i+1)-1),......,第63区间(4227858432
- 4294967259)。intArray分别记录每个区间出现的数的个数,肯定至少有一个区间上的计数少于67108864.利用这一点可以快速找出一个没有出现过的数。
第一遍遍历40亿个数过程如下:
1、申请长度为64的整型数组intArray[64],占用内存空间为64*4B;
2、遍历40亿个数,如果当前数为num,则num / 67108864 = i,那么intArray[i]++;
3、然后遍历intArray数组,找出一个计数小于67108864的位置k。
找出位于某个区间 k 的所有数之后,再从中找出一个没有出现过的数,则问题就解决了。申请一个长度为67108864的bit数组,数组每个位置有两个状态 0和1,如果第 k区间出现的数就赋值为1,没有出现就是0,最后遍历一下bitArray,就可以找到状态是0的一个数,就是没有出现过的那个数。
第二遍遍历40亿个数过程如下:
1、申请长度为67108864的bit数组bitArray[67108864],占用内存空间大约8MB;
2、再遍历40亿个数,这次只需要找出位于区间 k 的所有数,如果 n / 67108864 == k,那么n属于k区间;
3、在第2步的找出的 n,将bitArray[n - 67108864*k]的值置为 1,只做第k区间上数的bitArray映射;
4、遍历完成之后,在bitArray上必然存在状态是0的位置,假设第 i 个位置没被设置成1,那么67108864*k + i这个数就是有个没有出现过的数。
如此两遍遍历问题就得到解决。
相关文章推荐
- CRC校验之模2除法(学习笔记、备忘)
- MongoDB使用中的一些问题
- 学习笔记:发现一个IE版本判断的好方法
- Linux----mktemp命令的用法
- HDU 1754 I Hate It(线段树单点替换/区间最值)
- intltool 的安装!!
- get()函数读顺序文件(C/C++源程序)
- 【设计模式】依赖倒置原则
- 多个授权文件共存的正确方法
- jsp网页在线编辑器
- CSS3
- nyoj 最长公共子序列 36 (简单LCS模板)
- XML::Parser perl module is required for intltool错误
- jQuery复制表单元素
- A different object with the same identifier value was already associated wit
- MYSQL主从同步故障一例及解决过程!
- Solr 3.5 + Tomcat7 + mmseg4j + 搜狗词库 -配置并运行
- Flume学习8_Flume1.5.0入门:安装、部署、及flume的案例
- oracle中的to_char数字转换为字符串格式
- 由中序遍历和后序遍历构造二叉树