Leetcode 137:只出現一次的數字 II(最詳細的解法!!!)
阿新 • • 發佈:2018-11-11
給定一個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現了三次。找出那個只出現了一次的元素。
說明:
你的演算法應該具有線性時間複雜度。 你可以不使用額外空間來實現嗎?
示例 1:
輸入: [2,2,3,2]
輸出: 3
示例 2:
輸入: [0,1,0,1,0,1,99]
輸出: 99
解題思路
這是之前Leetcode 136:只出現一次的數字(最詳細的解法!!!)問題的擴充套件。我們直接使用xor
的方法不行,因為我們這裡是三個元素,所以我們無法完成消除。但是我們可以通過dict
記錄元素個數,最後判斷出現次數為1
的是誰即可。
class Solution:
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
nums_dict = {}
for num in nums:
nums_dict[num] = nums_dict.get(num, 0) + 1
for key, val in nums_dict.items():
if val == 1:
return key
我們如果不是用額外空間怎麼做呢?我們可以使用set
得到nums
中所有不重複的元素,通過這些不重複的元素和的三倍減去原來nums
的和,得到的結果就是單個元素的兩倍。
class Solution:
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
return (3*sum(set(nums)) - sum(nums))//2
這個問題其實還是可以通過邏輯運算來解決。我們想一想我們之前Leetcode 268:缺失數字(最詳細的解法!!!)
xor
?其本質就是想通過兩個元素相互消除。那麼我們這個問題其實本質就是希望三個元素相互消除。那麼這要怎麼做呢?我們不再是通過一個元素記錄狀態,我們可以通過兩個元素來記錄狀態的轉化,例如
a b
0 0 0
1 x 0
2 0 x
3 0 0
首先我們會定義兩個變數a
和b
,當遍歷nums
的時候,對於重複元素x
,第一次碰到x
的時候,我們會將x
賦給a
,第二次碰到後再賦給b
,第三次碰到就全部消除。賦值和消除的動作可以通過xor
很簡單的實現。所以我們就可以寫出這樣的程式碼
a = (a^num)
b = (b^num)
但是上面寫法忽略了,只有當a
是x
的時候,我們會將0
賦給b
,那要怎麼做呢?我們知道如果b=0
,那麼b^num
就變成了x
,而x&~x
就完成了消除操作,而此時a=x
,所以第二行寫為
b = (b^num) & ~a
同理,我們應該將第一行改為
a = (a^num) & ~b
最後程式碼如下
class Solution:
def singleNumber(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
ones, twos = 0, 0
for num in nums:
ones = (ones^num) & ~twos
twos = (twos^num) & ~ones
return ones
如果我們將問題繼續推廣成如果輸入陣列中每個元素出現k次,只有一個元素出現p次,那個出現p次的元素是?
看這篇尋找特定數字問題
reference:
我將該問題的其他語言版本新增到了我的GitHub Leetcode
如有問題,希望大家指出!!!