題目:假設一個機器只存儲一個標號爲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);
}