给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数。

前几天遇到的一个程序,一看到40亿,直接蒙圈了,还以为要用到B树来查找呢,好吧,看算法~

//a, b, c, 都是三个等长的数组,alen表示其长度。bit表示位数。比如32位。bit = 32.
//re表示最后缺少的那个数。

int get_lost(int *a, int *b, int *c, int alen, int bit)
{
	int re = 0, v = 0, biter = 0, *t, citer, i = 0;
	if (!a || !b || alen == (unsigned long)((1 << bit)))
		return -1;  //哪个数与最多可能拥有个数相等的时候,直接返回了。   
	while (bit--)
	{
		v = (1 << bit);
		for (biter = citer = i = 0; i < alen; ++i)
		{
			if (a[i] & (1 << bit)) b[biter++] = a[i];
			else c[citer++] = a[i];
		}
		if (biter <= citer)
		{
			re += v;
			t = a; a = b; b = t;
			alen = biter;
		}
		else
		{
			t = a; a = c; c = t;
			alen = citer;
		}
	}
	return re;
}
思路:32位整数的范围是0~2^32(大于40亿),则对于一个随机40亿个整数来说,有2^32-40亿=294,967,296,约3亿个数不存在,即问题要在这3亿数内找一个出来。再看0~2^32这个范围,考虑到32位太长就以十六进制代替二进制进行表示:0x0000,0000~0xffff,ffff。如果全部包括2^32个数,则可以看到0和1的个数是相等的,即各自为50%的出现概率。假设32位整数A和32位整数B在第i个二进制位处分别是0和1,则认为A和B是i位互补数(在这里仅供说明参考用)。归纳推广,根据50%的出现概率,考虑任意一个二进制位时,都可以将2^32个数划分为2个互补数的集合,即A集合和B集合。如果任意一位二进制位的互补数缺失一个,那么在该位处的0,1出现概率肯定不等,缺失数所代表的二进制值(0/1)的概率肯定小于存在数所代表的二进制值(1/0)的概率,【选择较少的数是为了补全这50%的概率,也就是较少的数等于缺失数的原因】。所以来看算法实现,程序的作者依次比较每个二进制位时选择较少数作为结果是有理论依据了。当然,作者为了更好的快速收敛提高效率,每次迭代都在缩小待搜索整数的范围,即用alen来控制二进制位数。
这个解释很到位,粘来的~

你可能感兴趣的:(C++笔试题)