题目:假设一个机器只存储一个标号为ID的记录,假设每份数据保存2个备份,这样就有2个机器存储了相同的数据。其中ID是小于10亿的整数
问题1、在某个时间,如果得到一个数据文件ID的列表。是否能够快速的找到这个表中仅出现一次的ID?即快速找出出现故障的机器存储的数据ID。
问题2、如果有两台机器死机呢?(假设同一个数据的俩个备份不会同时丢失,即列表中缺少的是两个不等的ID)
———————————————————————————————————————
一份数据拥有一个独一无二的ID,备份数据的ID与原始数据的ID相同,备份数据与原始数据存储在不同的机器上。文件列表中的ID包含了两个机器的信息,所以如果某个机器坏掉,文件列表当中这存在一个关于数据的ID
对于问题1,最直观的方法就是遍历文件列表,技术每一个数据文件出现的次数。此时时间复杂度为O(n),由于要存储每一个ID的计数信息所以空间复杂度也为O(n)。
优化程序一般从时间复杂度和空间复杂度来考虑,很显然本题的时间复杂度没法再优化,只能尽可能优化空间复杂度。所以可以考虑用动态数组的方法,当遍历数据列表时,如果ID不在数组中就添加进去,如果数组中已存在对应的ID则从数组中删除相应的ID。这样空间复杂度就相应的减少了。这样就可以找出所有丢失的ID
假设只有一个ID丢失,现在想要从中找出丢失的ID,利用异或方法(x^x=0,x^0=x,x^y=0),因为对应其他的ID数组中都有两个相同的值,异或运算满足交换律,结合律,所以对数组中的所有的ID进行异或运算,相同的ID异或后为0,则最后剩下的就是丢失的ID。
public static void second()
{
int[] id = {1,2,3,1,2};
int result = 0;
for(int i = 0;i < id.length;i++)
{
result = result^id[i];
}
System.out.print(result);
}
当有两个不同的ID丢失后,如何才能分别这两个ID,因为所有的ID异或之后得到的数是这两个丢失的ID异或而得到的。设x,y分别为丢失的ID,x与y异或的得到z(X^Y=Z),根据 Z的二进制表示从右到左第一个为1的位置b将所有的ID分成两类,一类为b位为1的一类为b位为0的,然后对两个类进行异或,得到x,y
//找出数组中仅出现一次的两个数
public static void thrid()
{
int[] id = {1,2,3,4,5,7,1,2,3,4};
int result = 0;
for(int i = 0;i < id.length;i++)
{
result = result^id[i];
}
int temp = result&1;
int count = 0;
while(temp == 0)
{
count++;
result = result>>1;
temp = result&1;
}
int i=0,j=0;
for(int k = 0;k<id.length;k++)
{
int ptr = id[k]>>count;
if((ptr&1) == 0)
{
i = i^id[k];
}
else
{
j = j^id[k];
}
}
System.out.println(i);
System.out.println(j);
}