【面试题】给40亿个无符号不重复且没排过序的数,查找一个数是否在这40亿个数之中 - 天涯海角 - CSDN博客 https://blog.csdn.net/peiyao456/article/details/53064755
2016年11月07日 11:24:11
看到这样一道面试题,我们不由的想到前边学习过的哈希表,哈希表查找效率高,唯独就是 空间浪费有点大。而在这道题目之中,40亿个无符号数(表明最高位表示大小),几乎涵盖了整形里的所有的数(总共42亿9千多)。而42亿9千多的数全部放到内存大约需要4G*4 = 16G,加上操作系统,各种运行软件,我们普通的计算机是无法运行这42亿数字的,除非超级计算机。所以,按照将每个数字都占用一个整形空间的方式导入内存的方式是不可取的。我们知道,数据在计算机中都是以二进制格式存储的,或0或1,我们不妨用每一个二进制位(比特位)来存储一个数,存在的话置为1,不存在置为0,这样的话,一个int可以表示32个数字。所有的数据会只占用到16G/32 = 500MB,一般的计算机还是可以满足这个请求的。40亿个数字,只能存储到硬盘,查找的时候导入内存就好了。下边给出实现代码~~~“
#pragma once #include<iostream> using namespace std; #include<vector> class BitMap { public: BitMap(size_t range) { _tables.resize((range >> 5)+1); } void Set(size_t num) { //确定num在第几个数 int index = num >> 5; //确定num在 index的哪一位 int pos = num % 32; //置位 _tables[index] |= (1 << pos); } void ReSet(size_t num) { int index = num >> 5; int pos = num % 32; _tables[index] &= (~(1 << pos)); } bool Test(size_t num) { int index = num >> 5; int pos = num % 32; return _tables[index] & (1 << pos); } protected: vector<size_t> _tables; }; void TestBitMap() { BitMap bm(-1); bm.Set(100); bm.Set(200); bm.Set(468); cout << "100:"<<bm.Test(100)<<endl; cout << "200:"<<bm.Test(200)<<endl; cout << "800:"<<bm.Test(800)<<endl; cout << "468:"<<bm.Test(468)<<endl; bm.ReSet(100); cout << "100:"<<bm.Test(100)<<endl; cout << "200:"<<bm.Test(200)<<endl; cout << "800:"<<bm.Test(800)<<endl; cout << "468:"<<bm.Test(468)<<endl; }
我们知道 -1 在计算机中的存储就是 11111111 11111111 11111111 11111111,转换成无符号数,就是 2^32-1,可以存储整形里的所有数字了~
上边的代码仅仅给出了几个数据的置位,复位及查找,对于大数据也是一样的。只不过数据应该从硬盘获取就可以了。下边关于代码做以详细解释~~
这样我们就能很快的判断一个数字是否在那个大数据之中了,然而对于这样的题目,还有另外一种方法:
对于给定的一个数,我们可以很快就得出这个数的二进制表示。用这个数的每一个比特位去从大数据中筛选:比如数据的最高位是0,我们就筛选出大数据中最高位是0的数,这样数据的多少大约就能减少一半,然后根据第二位继续进行筛选,依次类推,32次筛选就可以判断给定的数据是否在大数据中。这样的方法,相较于上边的做法还是有一定的缺陷,比如我们要查找几个数,上边的办法效率还是稍微高一点的~~