【算法】面試題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

先考慮上述問題的簡單版本:一個數組裏面只有一個數字出現一次,其他都出現兩次,請找出這個數字。

    這個問題可以可以使用用異或的性質解決。異或的性質:對於整數a,有

                         (1) a^a=0

                         (2)a^0=a

                         (2)a^b^c=a^(b^c)=(a^c)^b

    利用以上的性質,上面的題目的解法爲:


func singleNumbers(nums []int) int {
  xorSum := 0
  for _, v := range nums {
    xorSum ^= v
  }
  return xorSum
}

有了以上的基礎,解文章開始時提出的問題的思路如下:

  (1)對於出現兩次的元素,使用“異或”操作後結果肯定爲0,那麼我們就可以遍歷一遍數組,對所有元素使用異或操作,那麼得到的結果就是兩個出現一次的元素的異或結果。

  (2)因爲這兩個元素不相等,所以異或的結果肯定不是0,也就是可以再異或的結果中找到1位不爲0的位,例如異或結果的最後一位不爲0。

  (3)這樣我們就可以最後一位將原數組元素分爲兩組,一組該位全爲1,另一組該位全爲0。

  (4)再次遍歷原數組,最後一位爲0的一起異或,最後一位爲1的一起異或,兩組異或的結果分別對應着兩個結果。

複雜度:

  (1)時間複雜度:第一次循環,將所有元素異或得到對應結果,時間開銷爲O(n);第二次循環,找出第一次異或結果爲1的位,時間開銷爲O(32);第三次循環,根據爲1的位將元素分爲兩組進行異或得到兩個結果,時間複雜度爲O(n),所以總的時間複雜度爲T(n) = 2*O(n)+O(32) = O(n)。

  (2)空間複雜度:常數,因爲只分配了兩個空間用於結果的保存,因此空間複雜度爲常數。


func singleNumbers(nums []int) []int {
  tar := make([]int, 2)
  xorSum := 0
  for _, v := range nums {
    xorSum ^= v
  }
  div := 1
  for ; div & xorSum == 0; {
    div <<= 1
  }

  for _, v := range nums {
    if div & v == 0 {
      tar[0] ^= v
    } else {
      tar[1] ^= v
    }
  }
  return tar
}

 

 

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