找出陣列中兩個只出現一次的數字

2021-06-29 09:05:15 字數 1575 閱讀 7686

參考博文:

乙個整型陣列裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。要求時間複雜度是o(n),空間複雜度是o(1)。

陣列示例:

首先希望先把出現兩次的數字去掉,這需要用到異或運算的乙個性質:任何乙個數字異或它自己都等於0。遍歷一遍陣列,將所有數字都異或一遍,得到的結果就是兩個只出現一次的數字異或的結果:

arr := int

result := arr[0]

for i :=1; i < len(arr); i++

此時,result的結果就是5 ^ 6的結果:3。

然後,希望通過result找到這兩個數字。因為result是異或的結果,還是需要從異或運算的一些性質中找出思路。如果某一位上的二進位制數不同,異或結果為1(1 ^ 0 == 1),再看上面的result:

0101

^ 0110

= 0011

也就是說result中的兩個1表示5和6的二進位制中最後兩位不同,可以根據這個從陣列中找出這兩個數。假設我們知道5和6右起第一位不同,那麼通過判斷右起第一位是不是0就可以將陣列中所有數字分成兩個子陣列,乙個子陣列中右起第一位為0,另乙個右起第一位為1,即將乙個數 & 1,判斷是不是等於0。現在兩個子陣列中都包含乙個只出現一次的數字和成對的出現兩次的數字(出現兩次的數字肯定相等,那麼 &1 後要麼都是0,要麼都是1),之後再使用異或運算將出現兩次的數字去掉就可以了。

那麼現在還有乙個問題就是怎麼讓result的二進位制中只出現1個1呢?

我們希望將除右起第一位1之外的其他位都置0:

11100為例,右起第一位在中間,可以先11100 - 1,得到11011,此時第3位之後都變成了1,第3位變成0,第3位前面的保持不變,再^11100, 因為第3位之前的沒變,異或結果為0,第3位之後的都為1,最後&11100,就只保留第3位和之後的,因為第3位之後都為0,所以最後結果就只剩下第3位。

總結:11100 & (11100 ^ (11100 - 1)) == 00100

還有一種做法是:11100 & (-11100) == 00100,這是利用負數的補碼除符號位和右起第乙個1之外其他位都取反的性質,通過相與將取反的位變成0。

分析的有些囉嗦了,想把想到的東西都寫下來,還真有點難。

arr := int

result := arr[0]

for i :=1; i < len(arr); i++

// 此時result是兩個只出現一次的數異或的結果

b := result & -result // 只保留result中右起第乙個1,其他位置0

x, y :=0,0

for i :=0; i < len(arr); i++ else

}fmt.println("x=", x, " y=", y) // x= 5 y= 6

找出陣列中兩個只出現一次的數字

題目 乙個整型陣列裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。要求時間複雜度是 o n 空間複雜度是 o 1 解題思路 這個題目的突破口在 題目為什麼要強調有乙個數字出現一次,其他的出現兩次?我們想到了異或運算的性質 任何乙個數字異或它自己都等於 0。也就是說,如...

找出陣列中兩個只出現一次的數字

問題描述 乙個陣列中除了兩個數字之外,其餘數字均出現了兩次 或偶數次 請寫出程式查詢出這兩個只出現一次的數字,要求時間複雜度為o n 空間複雜度為o 1 問題分析 這是一道很新穎的關於位運算的面試題。首先考慮這個問題的乙個簡單版本 乙個陣列中除了乙個數字之外,其餘的數字均出現兩次,請寫程式找出這個出...

找出陣列中兩個只出現一次的數字

問題描述 乙個陣列中除了兩個數字之外,其餘數字均出現了兩次 或偶數次 請寫出程式查詢出這兩個只出現一次的數字,要求時間複雜度為o n 空間複雜度為o 1 問題分析 這是一道很新穎的關於位運算的面試題。首先考慮這個問題的乙個簡單版本 乙個陣列中除了乙個數字之外,其餘的數字均出現兩次,請寫程式找出這個出...