现在的位置: 首页 > 综合 > 正文

编程之美 1.5 快速找出故障机器

2018年01月19日 ⁄ 综合 ⁄ 共 2000字 ⁄ 字号 评论关闭

题意:

题目:假设一个机器只存储一个标号为ID的记录,假设每份数据保存2个备份,这样就有2个机器存储了相同的数据。其中ID是小于10亿的整数
问题1、在某个时间,如果得到一个数据文件ID的列表。
是否能够快速的找到这个表中仅出现一次的ID?即快速找出出现故障的机器存储的数据ID。
问题2、如果有两台机器死机呢?(假设同一个数据的俩个备份不会同时丢失,
即列表中缺少的是两个不等的ID)
扩展题、如果所有的机子都有三个备份,也就是说同一ID的机子有三台。
而且同时又有三台机子死机,还能用上面的方法解决吗?
如果有N台备份,又同时有N台机器死机呢?
相关问题、给你一副杂乱的扑克牌(不包括大小王),任意从其中抽出一张牌,
怎样用最简单的方法来知道抽出的是1~13中的那一张?(不要求知道花色)

解法一:

对于列表中的每一个ID,遍历列表查找是否存在相同的ID,利用数组记录每个ID出现的次数,
遍历完,次数小于2的就是要找的;
时间复杂度为O(N),空间复杂度为O(N)。空间复杂度在N很大时不理想。

解法二:

利用hash表。遍历列表,对于每一个ID,先检查hash表中是否有与之相同的ID,
若有,则从Hash表中删除该ID;否则,将该ID加入到hash表中。
这样,遍历完列表后,hash表中剩下的那一个元素即为所求ID。
时间复杂度为O(N),空间复杂度在最好的情况下为O(1),在最坏的情况下为O(N)。

解法三:

 利用异或运算,因为所以ID出现2次,只有一个出现一次,而a^a=0,
所以将这个列表中的所有ID异或后的值即为所求ID。
时间复杂度为O(N),空间复杂度为O(1)。在时间和空间上,基本已经达到最优。

 若是有2个ID仅出现一次,设为A和B,那么所有ID的异或值为A^B,无法确定A与B的值;
但是仍然可以找到,若A=B,A^B=0,则可以通过求和的方法A=B=(所有ID和-所以正常工作ID和)/2
若A!=B,A^B!=0,那么这个值最高为1,显然A与B当中有且只有一个数的相同位为1;

所以根据这一位,我们可以将a和b分开,并将数分成两组。
我们在结果数字中找到第一个为1的位的位置,记为第N位。
现在我们以第N位是不是1为标准把原数组中的数字分成两个子数组,
第一个子数组中每个数字的第N位都为1,第二个子数组的每个数字的第N位都为0。
所以把第N位为1的异或 结果num1, 把第N位为1的异或 结果num1,

#include<iostream>
using namespace std;

void FindTwoDifferentNum(int a[],int n,int &num1,int &num2)
//返回数组a中两个只出现一次的数字num1和num2
{
	int i,ans=0,k;

	for(i=0;i<n;i++)//先全部异或,其结果是这两个只出现一次的数字的异或
		ans^=a[i];
	
	num1=ans;//保存ans 
	
	k=0;//k表示的是第N位 a和b的不同 
	while((ans&1)==0)
	{
		ans>>=1;
		k++;
	}

	ans=num1;
	for(i=0;i<n;i++)//第n位不同 将全为1的异或 得到num1 
	{
		if((a[i]>>count)&1)
			num1^=a[i];
	}
	num2=num1^ans;//num1和全部异或的结果异或,就是num2
}

int main()
{
	int a[]={1,5,3,4,2,3,1,5,4,6};
	int num1, num2;
	FindTwoDifferentNum(a,sizeof(a)/sizeof(int),num1,num2);
	cout<<num1<<"  "<<num2<<endl;
}

解法四:

利用“不变量”。所有ID的和为一个不变量,对剩下ID求和。
所有ID的和与剩下ID的和之差即为所求ID。
由于所有ID之和可以事先算好,所以,该方法也可以在O(N)时间,O(1)空间内解决。

问题2,用2个方程解决
首先计算出初始未丢失之前,所有ID之和。  
然后计算出丢失之后的ID之和,然后(1)(2)结果进行相减操作,得到方程x+ y = a。  
利用丢失前后平方和之差,来与(2)进行联立,得到方程x*x+y*y=b。  
对两方程进行联立,即可以求出最终的结果。 

五、扩展问题 

如果同时有A个备份,同时有B台机器发生故障,怎么解决?

         在B小于4的情况下,还可以考虑采用解法四构造方程解决。但是,B超过4的情 况下,方程势必很复杂,建议采用解法三,当然,解法三需要改进。需要对存入Hash表的ID计数,当计数值达到A时再将这个ID从hash表中删除。

六、相关问题

给你一副杂乱的扑克牌(不包括大小王),任意从其中抽出一张牌,

怎样用最简单的方法来知道抽出的是1~13中的那一张?(不要求知道花色)?

         直接采用解法四;首先算好所有牌的和(1+...+13)x4=364,然后分别减去留下的牌点数,就得到抽出的是哪一张。

抱歉!评论已关闭.