机器故障有很多的机器,每一个机器都有一个ID,每一个机器都有一个备份。如果某一天有一个机器死机了,你能找到她吗? 这个问题的意思也就是有一个ID的列表,其他的ID都出现2次,只有这个死机的ID出现一次。好比很多数中找出只出现一次的数。很简单吧。利用数组保存ID出现次数,遍历一次就找到了。时间复杂度O(n),空间复杂度也是O(n)。 可是如果ID数量多达几亿呢,你不是很拙计吗?哦,可是动态申请数组,如果出现不同的ID就给他删除。这样空间复杂度最坏同样是O(n)。再想一想,想起来水王哥。这和那个问题是一样的,只不过是求出现一次的ID。这样ID列表肯定是奇数啦。删除到最后得到的肯定是出现一次的ID,这个就不详述了,详见水王哥问题。 还有别的方法吗?可以比水王哥问题还简单吗?哦,位操作,前天刚学过。两个相同的ID异或得到0,如果全部的ID异或,那得到的就是仅仅出现一次的ID。时间复杂度是O(n),空间复杂度是O(1),nice算法哈。这个代码就很简单了,不写了。(ID=0,ID^=Id[i];) 可是,如果是两台机器死机了呢?你还能找到这两个ID吗?拙计吗?好好思考一下。这还是和位操作有些关系的。 我们想一想如果所有的ID异或,最后得到的ID=Id[a]^Id[b]。我们用什么办法求?这样ID列表肯定是偶数啦。这样异或后的ID的二进制中的1肯定只是这两个ID中的某一个中的1 。如果我们最后的ID按某一位上有1给他分成两类,这样分别异或,肯定也会分别得到最后的Id,很nice吧。 编码实现
#include<iostream>
using namespace std;
const int N=10; //必然是偶数
int main()
{
int Id[N]={1,7,3,4,1,2,3,4,5,2};
int Id1,Id2; //两个死机的ID
int ID=0;//ID=id1^id2
Id1=Id2=0;
for(int i=0;i<N;i++)
ID^=Id[i];
for(int j=0;j<sizeof(int)*8;j++)
{
if((ID>>j)&1==1) //第j位为1
break;
}
for(i=0;i<N;i++)
{
if((Id[i]>>j)&1==1) //按第j位是否为1分类
Id1^=Id[i];
else
Id2^=Id[i];
}
cout<<"Id1="<<Id1<<endl;
cout<<"Id2="<<Id2<<endl;
return 0;
}
可是,假设ID有重复的,死机的那两个ID有肯定相同,这你还能这样做吗?哈哈,面试官这样一直逼问你,你跪不?NO,继续静心思考一下。 然后想到了二元一次方程中的变量与不变量。不变量是什么,是全部ID(包括死机的ID)的值,是他的和,他的乘积,等等。如果事先有全部ID的和、乘积。我们再求现有ID的和、乘积,很明显我们能够得到一个二元一次方程。这样求解就很简单了。时间复杂度是O(n),空间复杂度是O(1)。 可是求乘积的话,很多ID相乘可能会溢出啊。。我们可以用平方和,ID的平方求和。也同样得到结果。这个方法同样适用于ID不同的两个死机问题。编码实现就太简单了。 如果我问你,如果每台机器3个备份,这时候有3台机器死机呢?上述那种方法还是可以用的?用方程法来求解完全没有问题啦。所谓万变不离其宗。
转载请注明出处http://blog.csdn.net/sustliangbo/article/details/9289429