問題:假設乙個機器僅僅儲存乙個標號為id
的記錄(
id小於
10億的整數),每個資料儲存
2個備份,這樣就有
2個機器儲存了同樣的資料。
提問1
:某時間如果得到乙個資料檔案id
的列表,是否能夠快速地找出這個表中僅僅出現一次的
id?
提問2
:如果已經知道只有一台機器宕機(即只有乙個備份丟失)呢?如果有2
臺機器宕機(設同乙個資料的兩個備份不會同時丟失)?
解提問1轉換為有很多id
,其中只有乙個
id出現次數小於
2,其他正常
id出現次數等於
2,如何找到這個次數為1的
id。解法一 遍歷計數
思路:遍歷id
列表,用乙個陣列記下每個
id出現的次數,遍歷完畢後出現次數小於
2的就是所需結果。
時間複雜度為o(n)
,空間複雜度為
o(n)。
缺點:當id
數量多達即
g時,空間複雜度效率明顯出現問題,能否減小空間複雜度,對於出現2次的
id可以刪除,因為已經不符合條件。解法二就是這個思路。
解法二 遍歷列表對於出現次數為2 的id
不儲存,
利用hash
表記下每乙個
id的出現次數,遇見乙個id向
hash
表中增加乙個元素,如果
id的出現次數為
2,則將其從
hash
表中刪除,最後剩下的就是所需id。
演算法空間複雜度為最好為o(1
),最差仍為
o(n)。
解法三 異或運算
試圖進一步降低空間複雜度,若要繼續降低空間複雜度就有摒棄遍歷列表計數這種方法。將列表中的id
進行異或由於問題一中除所求
id外都出現
2次,故對列表中的
id進行異或後得到的結果就是出現次數為1的
id。
缺點:上述針對只有乙個id
出現次數為
1的情況,出現多次則不可行。
解提問2有2個id
(設為a,b
)僅僅出現一次,解法一二適用,但解法三所有
id的異或值為
a⊕b,無法確定a,
b的值。
書中分情況討論
② a=b時,則
a=b=
(所有id
之和—所有正常工作機器
id之和)/2。
②若a!=b
則a⊕b不為
0,但異或值的某一位為
1,那麼a和
b的相同位上也為1,將
id列表根據該位分為
2組,一組該位為
1,另一組該位為
0,每一類中分別含有a和
b,使用兩個變數遍歷列表時分別計算這兩類
id的異或值,即可得到
ab的值(因為對應組別中僅僅a或者
b出現一次,其他
id 都出現
2次)。
解法四 利用不變數
針對提問一將所有id
求和與宕機後的
id列表和相減即為宕機機器所存id
針對第二問 2個id
不同的情形
(1)計算未丟失之前所有id
和,計算丟失
id之後的和
(2)將上述2
和相減得到
a+b=p
;
(3)利用丟失前後的id
平方和之差與(
2)聯立求解
ab
書中第二個方程利用丟失前後id
的乘積求得
a*b的值,也提出乘積會導致溢位建議採用平方和。
擴充套件問題3個備份的時候,可有和,平方和,三者乘積得到
3個方程,
n個時會沒有足夠的方程無法求解。
撲克牌問題未抽取牌前的和減去抽取牌後的和即可。全部異或也可。
雜湊表 歸併排序,快速排序
程式設計之美 找出故障機器
給出乙個數字的列表,是否能夠快速的找出其中只出現一次的數字。想法 定義乙個動態的陣列,讀乙個數字,如果這個數字沒出現在動態陣列中,則將它放在陣列中,如果陣列中已經有了,則刪除。最後剩下的就是只出現了一次的資料。include include using namespace std void chec...
程式設計之美 1 5 快速找出故障機器
解法3 使用異或 問題1 找出出現奇數次的兩個數 void findrepeatedtwonumbers int a,int n,int no1,int no2 temp的值現為兩個出現奇數次的數的異或 找第乙個為1的位 for j 0 j sizeof int 8 j 第j位為1,說明這兩個數字在...
程式設計之美 1 5 快速找出故障機器
題目 假設乙個機器只儲存乙個標號為id的記錄,假設每份資料儲存2個備份,這樣就有2個機器儲存了相同的資料。其中id是小於10億的整數 問題1 在某個時間,如果得到乙個資料檔案id的列表。是否能夠快速的找到這個表中僅出現一次的id?即快速找出出現故障的機器儲存的資料id。問題2 如果有兩台機器宕機呢?...