程式設計之美之找出故障機器

2021-07-11 17:07:59 字數 2337 閱讀 3396

問題:假設乙個機器僅僅儲存乙個標號為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 如果有兩台機器宕機呢?...