目录
一:面试题:给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。【腾讯】
首先:40亿个整数要占用多少空间?
先来回顾一下:
1G = 1024MB
1024MB= 1024*1024 KB
1024*1024 KB = 1024*1024*1024 Byte = 2^30 Byte = 大约10亿 Byte
40亿个字节 = 4 G,所以4*4 = 16 G
以下两种方法内存消耗太大:
第一种方法:排序+二分查找
第二种方法:40亿个数放进一个set/unordered_set,查找 x 在不在,因为会有额外的附带消耗,left,right,parent,col.
===》节省内存的角度出发:使用2^32个比特位的位图进行映射,2^32 bit = 2^29 Byte
因为2^30 Byte = 10亿 Byte = 1G ,所以2^29 Byte = 512 MB

对于一个数x如何映射他的位置:
- // 把x映射的比特位设置成1
- void set(size_t x)
- {
- // 计算出他是第i个char对象中
- size_t i = x / 8;
- // 计算出他在这个char的第j个比特位上
- size_t j = x % 8;
-
- _bits[i] |= (1 << j);
- }
- // 把x映射的比特位设置成0
- void reset(size_t x)
- {
- // 计算出他是第i个char对象中
- size_t i = x / 8;
- // 计算出他在这个char的第j个比特位上
- size_t j = x % 8;
-
- _bits[i] &= (~(1 << j));
- }
如何判断一个数是否是1:
- bool Test(size_t x)
- {
- //计算出他是第i个char对象中
- size_t i = x / 8;
- //计算出他在这个char的第j个比特位上
- size_t j = x % 8;
-
- return _bits[i] & (1 << j); //0就是假,非0就是真
- }
解决方法:用2个比特位标识一个值——消耗1G的内存
不在: 00
出现一次:01
出现多次:10
template<size_t N> class FindOnceValSet { public: void set(size_t x) { bool flag1 = _bs1.test(x); bool flag2 = _bs2.test(x); // 00 -> 01 if (flag1 == false && flag2 == false) { _bs2.set(x); }// 01 -> 10 else if (flag1 == false && flag2 == true) { _bs1.set(x); _bs2.reset(x); } // 10 -> 10 不处理,标识已经出现多次 } void print_once_num() { for (size_t i = 0; i < N; ++i) { if (_bs1.test(i) == false && _bs2.test(i) == true) { cout << i << endl; } } }
给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址? 与上题条件相同,如何找到top K的IP?
