題目:
題目鏈接: https://leetcode-cn.com/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/
解題思路:
方法一:異或,時間O(N),空間O(1)
如果只有一個數字不重複,那隻要從第一個數字異或到最後一個數字的結果,就是不重複的數字
但是如果有兩個數字不重複,那異或的結果,就是兩個不重複數字的異或結果
如果能夠把兩個數字分到兩組,其他數字保證相同的數字分到一組,那對兩組數字分別進行異或操作,最後就可以得到這兩個不同的數字了
所以在對所有數字異或操作,獲得一個新的數字之後,從新的數字中,選取一個二進制表示中是1的位,說明這一位在兩個要找的數字中一個爲0,一個未1
根據這一位進行分組,可以保證將兩個要找的數字分到兩個組裏,並且其餘相同的數字在同一組
方法二:二分,時間O(NlogN),空間O(N)
這種方法效率比第一種低,但是覺得思路挺好的,也記錄下來
原題解鏈接: 什麼?這題還可以用二分查找?🤷♀️必須秒懂!
大致思路爲:
- 先遍歷數組,尋找最大的數字right和最小的數字left
- 然後根據中間數組mid = (left + right) / 2進行分組,也是分別進行異或操作
- 如果兩組數組中,有一個數字爲0,說明兩個要尋找的不重複數字在同一組,更新left或者right,再次進行分組異或,直到兩組數字的最終異或結果都不爲0
- 需要額外處理的情況,是可能兩個不重複數字中,有一個爲0,需要在第一次遍歷確定left和right的時候進行記錄數字0的個數
代碼實現:
方法一:
class Solution:
def singleNumbers(self, nums: List[int]) -> List[int]:
res_num = 0
for a in nums:
res_num ^= a
bit_pos = 1
while bit_pos < res_num:
if (res_num & bit_pos) == bit_pos:
break
bit_pos <<= 1
res = [0, 0]
for a in nums:
idx = 0 if (a & bit_pos) == 0 else 1
res[idx] ^= a
return res
方法二:
class Solution:
def singleNumbers(self, nums: List[int]) -> List[int]:
left = float('inf')
right = float('-inf')
res = 0
zero_num = 0
for a in nums:
left = min(left, a)
right = max(right, a)
if a == 0:
zero_num += 1
res ^= a
if zero_num == 1:
return [0, res]
while left <= right:
res = [0, 0]
mid = (left + right) // 2
for a in nums:
if a < mid:
res[0] ^= a
else:
res[1] ^= a
if res[0] != 0 and res[1] != 0:
return res
elif res[0] == 0:
left = mid
else:
right = mid
return res