快速找出故障机器

假设一个机器仅存储一个标号为ID的记录(假设ID是小于10忆的整数) 假设每份数据保存两个备份 这样就有两个机器存储了同样的数据

1.在某个时间 如果得到一个数据文件ID的列表 是否能够快速找出这个表中仅出现一次的ID

2.如果已经知道只有一台机器死机(也就是说只有一个备份丢失)?如果两台机器死机(假设同一个数据的两个备份不会同时丢失)?


问题1:

直接遍历表 利用一个数组记录下每个ID出现的次数 遍历完毕 出现次数小于2 的ID即仅出现一次的ID

假设有n个ID 空间复杂度和时间复杂度均为O(n)


对于该种方法改进 可以将出现2次的ID不必存储 因此可以用一个边长数组存储ID出现次数  但这种方法最好情况下空间复杂度为O(1) 最坏情况下仍为O(N)


ID成对出现的 表明数据未丢失 两个相同的数相异或的结果为0 因此将所有数据异或 得到的非0 结果 即为只出现一次的ID

这种方法只需要遍历ID数组一次 空间复杂度为O(1)


问题2:

可以利用异或的方法  但是这种方法只适合只有一台机器死机 而不适合同一个数据的两个备份同时丢失

将所有ID相与 得到一个不为0的结果 那么这个二进制的某一位为1 显然丢失的两个ID中有且仅有一个数该位上为1 

这样 将所有ID分为两类:一类该位上为1 另一类该位上为0 每一类都含有一个丢失的ID  然后对这两类ID进行异或 得到的值即为丢失的ID

#include <iostream>
using namespace std;
int Is1(int n,  int a)
{
	n = n>> a;
	return(n & 1);
}
 int last1(int n)
{
	int t = 0;
	while ( n )
	{
		t++;
		n = n >> 1;
	}
	return t;
}
void find2num(int A[], int n,int *a,int *b)
{
	if (A == NULL || n < 2)
		return;
	int t = 0;
	for (int i = 0;i < n;i++)
		t ^= A[i];
	int index = last1(t);

	*a = *b = 0;
	for (int i = 0;i <= n;i++)
	{
		if (Is1(A[i], index))
			*a ^= A[i];
		else
			*b ^= A[i];
	}

}
int main()
{
	int A[] = {1, 2,3,4,4,5,5,7,7,3 };
	int n = 10;

	int a = 0;
	int b = 0;
	find2num(A, n - 1, &a, &b);
	cout << a << ' ' << b << endl;
	return 0;
}


异或的方法不适同一个数据的两个备份同时丢失的情况 因此要寻求别的方法


我们可以通过构造方程 来求解丢失的ID

对于问题1 预先求出所有ID的和s1  然后再求出当前所有ID的和s2  这样s1-s2即为丢失的ID  该方法时间复杂度为O(N) 空间复杂度为O(1)

对于问题2  我们可以构造一个新的方程 来求解两个未知数  可以预先求出所有ID的平方和  然后求出当前所有ID的平方和 

也可以预先求出所有ID的乘机  然后再求出当前所有ID的乘积 。。。。。


该方法解决问题2  时间复杂度为O(N) 空间复杂度为O(1)


扩展问题:如果所有机器有3个备份 也就是说同一台ID的机器有3台 而且同时又有3台机器死机 ?


可以用构造方程的方法解决 不过解方程不是件容易的事情啊~



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值