题目:
有2.5亿个无符号整数(但在文件里面),要求找出这2.5亿个数字里面,不重复的数字的个数(那些只出现一次的数字的数目);另外,可用的内存限定为600M;要求算法高效、最优。
思路:
这么多个数字,全部读到内存里面肯定不行的,那么就要读一些处理一些。试想用一个标志的数组,里面放的是true或者false,表示一个数字是否是第一次被读到,最好能够把这个数字就当做数组的下标来访问这个标志,比如读到234432,看flag[234432]是true还是false,这样就很方便了(这和哈希的思想不是挺类似的嘛)。
好了,那么现在主要矛盾在这个flag标志数组该如何定义上了。无符号int,大小从 0 到 2^32 - 1(4字节的话),那么要保证数组足够大以至于能够用下标 2^32 - 1 来访问这个数的标志。true或false,那么也只要一位就够了,那么这个flag数组有多大呢:
2^32 个bit 也就是 2^29 byte 也就 2^19 kb 也就 2^9 M 也就 512 M。这个大小小于600M,那么就内存来说是可以的。
代码:
1 #include <iostream> 2 #include <fstream> 3 #include <cstdlib> 4 #include <bitset> 5 6 using std::cin; 7 using std::cout; 8 using std::endl; 9 10 int main(void) 11 { 12 const unsigned int thisIntMax = 0xffffffff; //无符号int最大值,我的机子int是4字节 13 14 #ifdef GENETATE_DATA 15 //生成很多值,其实这里太多了 16 std::ofstream fout("src.txt"); 17 for (unsigned int i = 0; i < thisIntMax; i++) 18 { 19 unsigned int temp = std::rand(); 20 fout << temp << endl; 21 } 22 #endif 23 24 std::bitset<thisIntMax>* pArr = new std::bitset<thisIntMax>; //默认值都是0,所以不要设置值了 25 std::ifstream fin("src.txt"); 26 unsigned int temp, allCnt = 0, cnt = 0; 27 28 while (fin >> temp) 29 { 30 allCnt++; 31 if (false == pArr->at(temp)) //注意这里要用at 32 { 33 cnt++; 34 pArr->set(temp); //设为1 35 } 36 else 37 { 38 cout << temp << endl; 39 } 40 if (10000 == allCnt) 41 break; 42 } 43 cout << "Results:\n" << allCnt << endl << cnt; 44 delete pArr; 45 cin.get(); 46 }
结果:
总结:
用位来表明一个数是否出现过。
直接把数字当做位数组的下标来进行访问。