《編程之美》讀書筆記-1.5快速找出機器故障

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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章