返回
LeetCode-剑指Offer 56-1:独一无二的数字检测
后端
2024-02-19 15:08:52
剑指Offer 56-1:数组中数字出现的次数
在LeetCode的众多算法题中,剑指 Offer 56-1:数组中数字出现的次数无疑是一个经典而颇具挑战性的题目。它要求我们在一个整型数组中找出两个只出现一次的数字,且时间复杂度必须是O(n),空间复杂度是O(1)。
面对这样的挑战,我们不能使用常见的暴力求解方法,而是需要借助巧妙的数学技巧和位运算的魅力。下面,我们就来一步步拆解这道题,探索其背后的奥秘。
## 算法思想
首先,我们来分析题目的本质。我们可以将数组中的数字分为两组:一组是出现两次的数字,另一组是出现一次的数字。为了找出只出现一次的数字,我们需要想办法将这两组数字区分开来。
这里,我们可以利用位运算的异或(XOR)操作。异或运算的特性是:相同为0,不同为1。也就是说,如果两个数字进行异或运算,结果将是它们二进制表示中不同的位。
基于这个特性,我们可以将数组中的所有数字进行异或运算。这样,只出现一次的数字将异或为一个非零的值,而出现两次的数字将异或为0。
## 代码实现
了解了算法思想后,我们就可以开始编写代码了。
首先,我们需要将数组中的所有数字进行异或运算,得到一个非零值。
```python
def find_single_numbers(nums):
# 异或所有数字
xor = 0
for num in nums:
xor ^= num
# 找到一个异或结果中为1的位
bit = xor & -xor
return find_single_numbers_with_bit(nums, bit)
```
接下来,我们需要找到异或结果中为1的位,即只出现一次的数字在二进制表示中与众不同的那一位。
```python
def find_single_numbers_with_bit(nums, bit):
# 根据bit位将数组分为两组
group1 = []
group2 = []
for num in nums:
if num & bit:
group1.append(num)
else:
group2.append(num)
# 分别异或两组数字,得到只出现一次的数字
single1 = 0
for num in group1:
single1 ^= num
single2 = 0
for num in group2:
single2 ^= num
return [single1, single2]
```
最后,我们将数组分为两组,分别异或每组中的数字,即可得到只出现一次的两个数字。
## 复杂度分析
上述算法的时间复杂度是O(n),因为我们只需要遍历数组一次。空间复杂度是O(1),因为我们只需要几个变量来存储中间结果。
## 总结
通过这道题,我们不仅学习了位运算的巧妙应用,还体会到了算法设计的重要性。在解决问题的过程中,我们需要开动脑筋,寻找最优解,才能在有限的时间和空间内完成任务。