leetcode面試題56 - I. 數組中數字出現的次數

leetcode56.題目描述

一個整型數組 nums 裏除兩個數字之外,其他數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)。

解題思路:要求時間複雜度爲o(n),空間複雜度O(1),如果沒有這些要求,這題很簡單,直接用set去重,遍歷數字用字典統計個數,輸出個數爲1 的key,結束。顯然空間複雜度並不滿足。
  別問我爲什麼會這題,只能告訴你我之前看過,一直覺得位運算的題都很巧妙,沒見過確實很難想出來。從本題的初級版本的開始吧。
  一個整型數組 nums 裏除一個數字之外,其他數字都出現了兩次。要求時間複雜度是O(n),空間複雜度是O(1)。
舉個例子,比如輸入[1,2,1,2,3]需要輸出3,這裏需要用到位運算異或的性質和異或的交換性
12123=11223=31異或2異或1異或2異或3=1異或1異或2異或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呀

  首先就,把次數爲2分開很簡單,我們主需要對數據做一些限制,可以把偶數分這邊,奇數分另外一遍,這樣不就分開了;但是這樣分不能保證a和b能分別分到兩個組。目前我們只有ab異或的值,只能從這裏出發了,異或的結果能表現出a和b在哪些方面的信息呢,如果異或結果,首位爲0,說明a和b的首位相同,如果爲1說明a,b首位不同,通過找到a和b,不同的那位,那我們不就可以區分a,b。

  以下圖爲例子,4和5的異或結果爲001,如果把所有數和001求與,結果是不是就兩種情況,要麼爲0,要麼爲1,結果0的分爲一組,1的分爲一組,可以完美的把這nums分爲兩組,而且4和5能分開,次數爲2的數也在同一組,因爲相同的數對001求與結果肯定相同。

  大概做法就是,對數組遍歷異或,先求出a和b異或的結果,找到異或結果裏的首位爲1的數,加入是第四位,就用1000分別遍歷這個數組,能將大數組分爲兩個數組,再對數組分別遍歷異或得到a和b的值。代碼如下。
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]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章