異或算法

最近碰到不少經過巧妙着運用位運算來巧妙解決複雜問題的算法,今天分享的這道題,或許可以開拓你的一些算法思惟。算法

題目描述

有一組存放 ID 的數據。而且 ID 取值爲 0 - (N-1) 之間,其中只有一個 ID 出現的次數爲 1,其餘的 ID 出現的次數都等於 2,問如何找到這個次數爲 1 的 ID ?數組

解法一:巧用數組下標

不知道有多少人還記得我以前分享的巧用數組下標的技巧:一些經常使用的算法技巧總結優化

個人第一想法即是採用下標法來解決,把 ID 做爲數組 arr 的下標,在遍歷 ID 的過程當中,用數組記下每一個 ID 出現的次數,即每次遍歷到 ID = n,則 arr[n]++。spa

以後咱們在遍歷數組 arr,找到 arr[n] = 1 的ID,該下標 n 即是咱們要尋找的目的 ID。3d

這種方法的時間複雜度爲 O(N),空間複雜度爲 O(N)。get

解法二:巧用哈希表

顯然時間複雜度是沒法再下降的了,由於咱們必需要遍歷全部的 ID,因此時間複雜度最少都得爲 O(N)了,因此咱們要想辦法下降空間複雜度。io

你們想一個問題,假如咱們檢測到某個 ID 已經出現了 2 次了,那麼這個 ID 的數據咱們還須要存儲記錄嗎?大部分的 ID 都出現了 2 次,這一大部分的數據真的須要存儲嗎?效率

答是不用的,由於出現 2 次的 ID 不是咱們所要找的。因此咱們能夠優化解法一,咱們能夠採用哈希表來記錄 ID 出現的次數:利用哈希表記下每一個 ID 出現的次數,每次碰見一個 ID,就把這個 ID 放進 哈希表,若是這個 ID 出現了次數已經爲 2 了,咱們就把這個 ID 從哈希表中移除,最後哈希表只會剩下一個咱們要尋找的 ID。遍歷

這個方法最好的狀況下空間複雜度能夠下降到 O(1),最壞的狀況仍然了 O(N)。技巧

解法三:巧用位運算

那究竟有沒辦法讓空間複雜度在最壞的狀況下也是 O(1) 呢?

答是有的,按就是採用異或運算。異或運算有個特色:

異或運算特色

1,相同的兩個數異或以後,結果爲 0

2,任何數與0異或運算,其結果不變。

3,異或運算支持結合律

可見:A異或B =C

那麼 C異或A=B

因此,咱們能夠把全部的 ID 進行異或運算,因爲那些出現兩次的 ID 經過異或運算以後,結果都爲 0,而出現一次的 ID 與 0 異或以後不變,又由於異或支持結合律,因此,把全部 ID 進行異或以後,最後的結果即是咱們要找的 ID。

這個方法的空間複雜度爲 O(1),巧妙利用了位運算,並且運算的效率是很是高效的。

問題拓展

假若有 2 個 ID 出現的次數爲 1,其餘 ID 出現的次數都爲 2 呢?有該如何解決呢?是否仍是能夠用位運算呢?

爲了方便這裏咱們先假設 異或 的符號爲 @,

答是必須的,假如這兩個出現一次的 ID 分別爲 A, B,則全部 ID 異或後的結果爲 A@B,這時咱們遇到的問題是沒法肯定 A,B的值。

因爲 A 和 B 是不同的值,因此 A@B 的結果不爲 0,也就是說,這個異或值的二進制中某一位爲1。顯然,A 和 B 中有且僅有一個數的相同位上也爲 1。

這個時候,咱們能夠把全部 ID 分爲兩類,一類在這個位上爲 1,另外一類爲 0,那麼對於這兩類,一類會含有 A,另外一類會含有 B。因而,咱們能夠分別計算這兩類 ID 的異或值,幾可獲得 A 和 B 的值。

總結

你們作刷題的時候,不妨多加上一個想法:是否能夠用的上位運算這種思路。有收穫?不妨來個好看讓更多人看到這篇文章!

相關文章
相關標籤/搜索