算法题008 快速找出故障机器
快速找出故障機器
?
題目描述
關心數據挖掘和搜索引擎的程序員都知道,我們需要很多的計算機來存儲和處理海量數據。
然而,計算機難免出現硬件故障而導致網絡聯系失敗或死機。為了保證搜索引擎的服務質量,我們需要保證每份數據都有多個備份。
簡單起見,假設每個機器存儲一個標號為ID的記錄(ID是小于十億的整數),假設每份數據都保存兩個備份,這樣就有兩個機器儲存了同樣的數據。
1.在某個時間,如果得到一個數據文件ID的列表,是否能夠快速地找出這個表中僅出現一次的ID?
2.如果已經知道只有一臺機器死機(也就是說只有一個備份丟失)呢?如果有兩臺機器死機呢(假設同一個數據的兩個備份不會同時丟失)?
?
我的解法
這個題目肯定要考慮大量數據的處理,即需要重點考慮效率問題。
首先,ID是小于十億的整數,這說明用一個long型(4個字節)可以表示ID,不會超出表示范圍,所以這點不用擔心。
根據題目特點,得到ID列表后,可以考慮一種像是玩撲克牌游戲的做法,找一個數組來盛放遍歷的數(想象成摸牌),找到成對的就丟棄(或者你也可以把這個配對過程想象成連連看)。
最后將所有數字遍歷完之后還留下的就是單獨的ID。
這樣時間復雜度是O(n * n),因為需要摸n張牌,并且每摸一張牌都需要和手中的牌進行查詢配對。
下面是書中的解法,看完之后才知道我的解法真是弱爆了,為什么沒想到哈希表呢。
?
解法一
直接遍歷列表,利用一個數組記錄下每個ID出現的次數,遍歷完畢之后,出現次數小于2的ID就是我們想要的結果。
假設有N個ID,且ID的取值在0~N-1之間,這個解法占用的時間復雜度為O(N),空間復雜度為O(N)。
時間復雜度已經相當理想,但是空間復雜度不夠理想,如果ID的數量多達幾個G甚至幾十G,這樣的空間復雜度在實際的運算中就會帶來效率問題。
?
解法二
考慮到大部分ID的出現次數都等于2,這些ID的信息并不是必要的,所以不必存儲。
因此,可以把解法一數組中等于2的元素清空,然后用來存儲下一個機器ID的出現次數,這樣就可以減少需要的空間。
具體方法如下:遍歷列表,利用哈希表記下每個ID出現的次數,每次遇見一個新的ID,就向哈希表中增加一個元素;如果這個ID出現的次數為2,那么就從哈希表中刪除這個元素,最后剩下的ID就是我們想要的結果。
這個算法的空間復雜度在最好情況下可以達到O(1),在最壞的情況下仍然是O(N)。
?
解法三
對于第一問,假設列表中僅有一個ID出現了一次,那么可以考慮用異或關系來幫忙找到結果。
因為異或運算的定義是相同為假相異為真,異或運算滿足交換律和結合律。
所以,所有ID的異或值就等于這個僅出現一次的ID。(兩兩相同的都得到0,0和任何值異或等于原來的任何值)
這種情況下,時間復雜度為O(N),空間復雜度為O(1)。
?
對于第二問,由于有兩個ID僅出現了一次,設它們為A和B,那么所有ID異或的結果是A異或B,但還是無法確定A和B的值。
可以進行分類討論:
(1)A == B
這時A異或B等于零,丟失的是同一份數據的兩個拷貝,可以通過求和的方法求得A和B,即,所有ID值的和減去所有正常的ID之和,除以2得到A和B。
(2)A !=B
這時A異或B不等于零,那么這個異或值的二進制位中某一位為1,此時A和B中有且僅有一個數的相同位上也為1。
我們就把所有的ID分成兩類,一類在這位上為1,另一類在這位上為0。A和B分別位于這兩類中。
我們分別計算這兩類的異或和,即可得到A和B的值。(太巧妙了!)
?
解法四
對于第一問,缺失一個ID:
預先計算并保存好所有ID的求和(“不變量”),順序列舉當前所有剩下的ID,對它們求和,然后用所有ID的求和減去當前剩下所有ID的和,結果就是死機的機器的ID值。
時間復雜度為O(N),空間復雜度為O(1),和解法三一樣是計算復雜度最優的算法。
?
對于第二問,我們考慮所有的情況,即兩個ID可以相同也可以不同。
用上面的方法可以得到這兩個ID的和。我們構造出一個方程: x + y = a; a已知。
第二個方程有很多構造方法,比如可以用所有ID的乘積計算出另一個不變量,除以所有剩下的ID,結果得到兩臺死機機器的ID的乘積,即x * y = b。
這樣聯立兩個方程之后,可以解出x和y的值。
時間復雜度為O(N),空間復雜度為O(1)。
第二個方程構造也可以考慮平方和的方法。
?
參考資料
《編程之美》1.5節
總結
以上是生活随笔為你收集整理的算法题008 快速找出故障机器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用python编写daemon监控进程并
- 下一篇: 服务器安全浅谈