40亿个非负整数中找到未出现的数

32位无符号整数的范围是0 ~ 4 294 967 295,现在有一个正好包含40亿个无符号整数的文件,所以在整个范围中必然有未出现过的数。怎么找到所有未出现过的数?

要求: 可以使用最多1GB的内存。
进阶: 内存限制10MB,但是只用找到一个没出现过的数即可。

常规方法:假设用哈希表来保存出现过的数,那么如果40亿个数都不同,则哈希表的记录数为40亿条,存一个32位整数需要4B,所以最差情况下需要40亿×4B = 160亿字节,大约需要16GB的空间,不符合要求。

思路:
① 使用bit map的方式来表示数出现的情况,申请一个长度为4 294 967 295的 bit 类型的数组 bitArr(大约需要 0.5GB内存),bitArr上的每个位置只可以表示 0 或 1 状态。遇到num,就把 bitArr[num] 设置为 1。
② 再次遍历,bitArr下标为 0 的数就是40亿个数中未出现的数。

进阶: 用分区间的方式处理,只有10MB,但只要求找到其中一个没出现过的数。首先,将0~4 294 967 295 分成64个区间,每个区间是67 108 864个数,第0个区间(0 ~ 67 108 863)、第 1 个区间(67 108 864 ~ 134 217 728)…第63 个区间(4 227 858 432 ~ 4 294 967 295)。

  1. 第一次遍历。统计落在每一个区间上的数有多少。申请长度64的整型数组
    countArr[0…63],countArr[i] 用来统计区间 i 上的数有多少。遍历40亿个数,
    根据当前数计算出哪一个区间上的计数增加。
    比如,3 422 552 090,3 422 552 090 / 67 108 864 = 51,所以第51个区间
    上的数字增加countArr[51]++,遍历完后,必然会有一个区间的计数小于
    67 108 864。
  2. 再进行第二次遍历。申请长度67 108 864的bit map,这占用大约8MB的空
    间,记为 bitAArr[0…67108863]。此时只关注第 K 个区间,将bitArr[num -
    67 108 864*K] 的值设置为1,也就是只做第 K个区间的映射。
  3. 在 bitArr[i] 上必然存在一个没有被设为1的位置,那么 67 108 864 * K + i
    这就是没出现的数。

精简解法:

  1. 根据10MB的内存限制,确定统计区间的大小,就是第二次遍历时
    bitArr的大小。
  2. 利用区间计数的方式,找到计数不足的区间,这个区间肯定有没出现
    的数。
  3. 对这个区间上的数做bit map映射,再遍历bit map,找到一个没出现的
    数即可。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值