leetcode56.題目描述
一個整型數組 nums 裏除兩個數字之外,其他數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)。
解題思路:要求時間複雜度爲o(n),空間複雜度O(1),如果沒有這些要求,這題很簡單,直接用set去重,遍歷數字用字典統計個數,輸出個數爲1 的key,結束。顯然空間複雜度並不滿足。
別問我爲什麼會這題,只能告訴你我之前看過,一直覺得位運算的題都很巧妙,沒見過確實很難想出來。從本題的初級版本的開始吧。
一個整型數組 nums 裏除一個數字之外,其他數字都出現了兩次。要求時間複雜度是O(n),空間複雜度是O(1)。
舉個例子,比如輸入[1,2,1,2,3]需要輸出3,這裏需要用到位運算異或的性質和異或的交換性
這裏^符號打出來就報錯,用中文代替了,可以看出相同的數異或就變成0了,遍歷一次兩次的數都能爲0,最後剩下一個數字和0異或還是本身。代碼如下。這裏用到reduce高階函數,對可迭代對象進行逐個的輸入到函數中,然後把上次的結果和當前值輸入到lambda函數中去,lambda函數是一個異或函數。
from functools import reduce
def find_onetimenum(nums):
res = reduce (lambda x,y:x^y, nums)
return res
有了上面的經驗,我們可以將所有的數也遍歷異或一次。得到的結果就是剩下的兩個次數爲1的數a和b,即a^b,光知道這兩個數的異或結果,也無法知道a和b分別是多少。
如果能通過這個結果,把這個數組分爲兩個數組多好,其中一個數組包含a,和若干次數爲2的數;另外一個包含b,和剩下次數爲2的數。即可實現下圖的效果,最後分別再進行一次遍歷異或就能分別得到a,b呀
以下圖爲例子,4和5的異或結果爲001,如果把所有數和001求與,結果是不是就兩種情況,要麼爲0,要麼爲1,結果0的分爲一組,1的分爲一組,可以完美的把這nums分爲兩組,而且4和5能分開,次數爲2的數也在同一組,因爲相同的數對001求與結果肯定相同。
from functools import reduce
class Solution:
def singleNumbers(self, nums: List[int]) -> List[int]:
#獲取nums數組a,b的異或結果
res = reduce(lambda x,y:x^y,nums)
h = 1
#找到res最高位數爲1的數
while((res&h)==0):
h<<=1
a = 0
b = 0
#分組並異或遍歷,得到最終異或
for i in nums:
if i&h:
a ^= i
else:
b ^= i
return [a,b]