32位无符号整数的范围是0 ~ 4 294 967 295 现在有40亿个无符号整数,可以使用最多1GB的内存,找出所有出现了两次的数。
补充问题: 可以使用最多10MB的内存,怎么找到40亿个整数的中位数?
原问题: 可以用 bit map 来表示数出现的情况。
- 申请一个长度为 4 294 967 295 × 2 的bit类型的数组bitArr,1B占用8
个bit,所以长度为 4 294 967 295 × 2 的bit类型的数组占用1GB空间,
用2个位置表示一个数出现的词频。 - 怎么使用bitArr数组?遍历这40亿个无符号数。
① 如果第一次遇到num,就把 bitArr[num2] 和 bitArr[num2 + 1]
设置为01;
② 如果第二次遇到num,就把 bitArr[num2] 和 bitArr[num2 + 1]
设置为10;
③ 如果第三次遇到num,就把 bitArr[num2] 和 bitArr[num2 + 1]
设置为11;
④ 以后再遇到num,发现 bitArr[num2] 和 bitArr[num2 + 1]已经
被设置为11,就不再做任何设置。 - 再次遍历bitArr,如果发现bitArr[i2] 和 bitArr[i2 + 1]设置为10,那么
i 就是出现了两次的数。
补充问题: 用分区间的方式处理。长度为2MB的无符号整型数组占用的空间为8MB,所以区间的数量定位 4 294 967 295 / 2M,向上取整2148个区间。第0个
区间 0 ~ 2M-1,第1个区间 2M ~ 4M - 1,第 i 个区间为2M × i ~ 2M
× (i+1) - 1,…
- 申请一个长度2148个无符号整型数组 arr[0…2147],arr[i] 表示第 i 个
区间有多少个数。遍历40亿个数,看num落在哪个区间上(num/2M),
然后arr[num/2M]++。 - 通过累加每个区间的出现次数,就可以找到40亿个数的中位数到底落在
哪个区间。
比如,0 ~ K - 1区间上数的个数为19.988亿,但是发现当加上第 K 个
区间上数的个数之后就超过了 20亿,那么就可以知道第20亿个数是第
K个区间上的数,并且可以知道第20亿个数是第 K 个区间上的第0.002
亿个数。 - 接下来申请一个长度为 2MB的无符号整型数组 countArr[0…2M - 1]。
再次遍历40亿个数,只对第 K 个区间上的数numk做词频统计 ,将
countArr[numk - K*2M]++,最后在第 K 个区间找到第 0.002亿个数。