異或巧用,一道令我汗顏的演算法題——減小時間空間複雜度

weixin_33807284發表於2019-03-04

寫在前面

我們不是計算機專業的,卻一直對計算機演算法感興趣,也一直致力於減小自己程式的複雜度[捂臉],昨日吃飯時,某老鐵考我一道演算法題,思索良久,輾轉反側,夜不能寐,遂厚著臉皮去問答案,然則令吾汗顏,果真是一波騷操作……

看題!

給定一個非空整數陣列, 除了某個元素只出現一次以外, 其餘每個元素均出現兩次, 找出那個只出現了一次的元素。

說明:

你的演算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?

示例 1:

輸入: [2,2,1]    
輸出: 1

示例 2:

輸入: [4,1,2,1,2]     
輸出: 4

看答案之前,不妨獨立思考一下,看看能不能想出解決方案!

推薦先想一會兒


如果實在想不出來, 可以看一下提示 繼續想 !!

clipboard.png

提示

看一下標題!!!

clipboard.png

題目解析

根據題目描述,由於加上了時間複雜度必須是O(n),並且空間複雜度為O(1)的條件,因此不能用排序方法,也不能使用map資料結構

我們想了一晚上,結果, 答案是使用 位操作Bit Operation 來解此題。

將所有元素做異或運算,即 a[1] ⊕ a[2] ⊕ a[3] ⊕...⊕ a[n],而結果就是那個只出現一次的數字,時間複雜度為O(n)。

什麼??你忘記了異或???

異或運算 A ⊕ B 的真值表如下:

A B A ⊕ B
False False False
True True True
True False True
False True True

即:不相等即為True
而兩個相等 的數做異或操作為0
而任何數與0做異或操作都等於其本身

題目進階

有一個 n 個元素的陣列,除了兩個數只出現一次外,其餘元素都出現兩次,讓你找出這兩個只出現一次的數分別是幾,要求時間複雜度為 O(n) 且再開闢的記憶體空間固定(與 n 無關)

示例 :

輸入: [1,2,2,1,3,4]     
輸出: [3,4]

題目再解析

根據前面找 一個 不同數的思路演算法,在這裡把所有元素都異或,那麼得到的結果就是那兩個只出現一次的元素異或的結果, 為了敘述方便, 我們這裡把這個結果簡單記為字母 K

因為這兩個只出現一次的元素一定是不相同的,所以 K 一定不為零, 將K從左往右數的第一個為1的位記錄下來。

再然後,以這一位是 1 還是 0 為標準,將陣列的 n 個元素分成兩部分。

將這一位為 0 的所有元素做異或,得出的數就是隻出現一次的數中的一個

將這一位為 1 的所有元素做異或,得出的數就是隻出現一次的數中的另一個。

這樣就解出題目, 忽略尋找不同位的過程,總共遍歷陣列兩次,時間複雜度為O(n)。

舉個例子吧

假如:
輸入是: [1,2,2,1,3,4,7,7] 
進行異或操作:

>>> 1^2^2^1^3^4 # python的異或操作符
7

異或完畢為70000 0111
數字7從左往右數的第一個為1的位為

0000 0111
      ^

也就是第六位
以這一位是 1 還是 0 為標準,將陣列的 n 個元素分成兩部分
(也就是陣列大於等於4的分一組, 小於4的分一組)
即[4, 7, 7] 和 [1,2,2,1,3]

>>> # 陣列[4,7,7]所有元素做異或操作
>>> 4^7^7
4

>>> 陣列[1,2,2,1,3]所有元素做異或操作
>>> 1^2^2^1^3
3

大功告成!!

據該老鐵說此題來源於 LeetCode 第 136 號問題:https://leetcode-cn.com/probl...

相關文章