LeetCode 面試題56 - I. 數組中數字出現的次數 | Python

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


題目


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

示例 1:

輸入:nums = [4,1,4,6]
輸出:[1,6][6,1]

示例 2:

輸入:nums = [1,2,10,4,1,4,3,3]
輸出:[2,10][10,2]

限制:

  • 2 <= nums <= 10000

解題思路


思路:異或,位運算

先說下異或的性質:二進制位同一位相同則爲 0,不同則爲 1。

再說說一下異或的規律:

  • 若兩數值相同,兩者的異或結果爲 0,(即是任何數與自身異或結果爲 0)
  • 任何數與 0 異或結果爲本身

同時異或是滿足交換律,結合律的(數學符合:⊕)

  • 交換律: a ⊕ b = b ⊕ a
  • 結合律: a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c

回來看本題,題目說明,【整型數組 nums 中,除兩個數字之外,其他數字都出現了兩次】。那麼根據交換律、結合律將相同數字進行異或運算,那麼相同數字都會變爲 0,再根據第二條規律,那麼剩下的出現一次的數字。

在這裏主要需要實現的如何確保將數組分成兩組,使得:

  • 只出現一次的數字,在不同的兩組;
  • 相同的數組出現在相同的組。

只有這樣,每組進行異或運算的時候,最終纔會剩下單獨的數字。那麼該如何進行分組?特別是如何將兩個不同的數字分到不同的組?

這裏說一下 & 運算性質:1 & 1 = 1, 1 & 0 = 0, 0 & 0 = 0。

假設有 a, b 兩個數值,a 與 b 的異或結果爲 c。

那麼將 c 用二進制形式表示爲:

cncn1...c1c0c_nc_{n-1}...c_{1}c_{0}

取其中一個進制位,cic_i,考慮 cic_i = 0 與 cic_i = 1 的含義。因爲兩個相同數字異或,結果爲 0,這在前面已經說明了,那麼 cic_i = 1,這裏則表示兩個數值是不等的(0 的二進制位不含 1)。這樣就可以以這個不爲 0 的 cic_i 作爲分組的依據,根據上面 & 運算的性質,運算結果該位爲 0,放到一組,否則放到另外一組。那麼現在要找的就是滿足 cic_i = 1 的這個位,原理上可以任取,這裏選取的是不爲 0 的最低位

當找到這樣的 cic_i = 1 的位時,

  • 因爲兩個數若是相同時,對應位都是相同的,那麼進行 & 運算時,結果是相同的,那麼一定會分到同一組中。
  • 兩數不同時,找到這樣不爲 0 的最低位的數時,兩者與其運算的結果爲 0 或不爲 0,那麼就可以將兩者區分開。

那麼分組之後各自進行異或,各組剩下的就是單獨的數字。

具體實現代碼如下。

代碼實現


class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:
        res = 0
        # 全員進行異或
        for num in nums:
            res ^= num
        
        # 找出不爲 0 的最低位
        # & 位運算的使用
        div = 1
        while (div & res == 0):
            div <<= 1
        
        # 進行分組
        p, q = 0, 0
        for num in nums:
            if num & div:
                p ^= num
            else:
                q ^= num
            
        return [p, q]

實現結果


實現結果


以上就是使用異或,位運算的思路,解決《面試題56 - I. 數組中數字出現的次數》問題的主要內容,題目主要的難度在於如何對數組進行分組,然後根據異或的規律性質進行求解。


歡迎關注微信公衆號《書所集錄》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章