如何巧妙着運用「位運算」來解決問題?


最近碰到很多通過巧妙着運用位運算來巧妙解決復雜問題的算法,今天分享的這道題,或許能夠開拓你的一些算法思維。

該問題是這樣的:

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

解法一:巧用數組下標

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

我的第一想法便是采用下標法來解決,把 ID 作為數組 arr 的下標,在遍歷 ID 的過程中,用數組記下每個 ID 出現的次數,即每次遍歷到 ID = n,則 arr[n]++。

之后我們在遍歷數組 arr,找到 arr[n] = 1 的ID,該下標 n 便是我們要尋找的目的 ID。

這種方法的時間復雜度為 O(N),空間復雜度為 O(N)。

解法二:巧用哈希表

顯然時間復雜度是無法再降低的了,因為我們必須要遍歷所有的 ID,所以時間復雜度最少都得為 O(N)了,所以我們要想辦法降低空間復雜度。

大家想一個問題,假如我們檢測到某個 ID 已經出現了 2 次了,那么這個 ID 的數據我們還需要存儲記錄嗎?大部分的 ID 都出現了 2 次,這一大部分的數據真的需要存儲嗎?

答是不用的,因為出現 2 次的 ID 不是我們所要找的。所以我們可以優化解法一,我們可以采用哈希表來記錄 ID 出現的次數:利用哈希表記下每個 ID 出現的次數,每次遇見一個 ID,就把這個 ID 放進 哈希表,如果這個 ID 出現了次數已經為 2 了,我們就把這個 ID 從哈希表中移除,最后哈希表只會剩下一個我們要尋找的 ID。

這個方法最好的情況下空間復雜度可以降低到 O(1),最壞的情況仍然了 O(N)。

解法三:巧用位運算

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

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

異或運算特點:相同的兩個數異或之后,結果為 0,任何數與0異或運算,其結果不變並且,異或運算支持結合律

所以,我們可以把所有的 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 的值。

總結

大家做刷題的時候,不妨多加上一個想法:是否可以用的上位運算這種思路。有收獲?不妨來個好看讓更多人人看到這篇文章!
最后推廣下我的公眾號:苦逼的碼農戳我即可關注,文章都會首發於我的公眾號,期待各路英雄的關注交流。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM