题目描述:
给你一个 非空 整数数组
nums,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
**输入:**nums = 2,2,1
**输出:**1
示例 2 :
**输入:**nums = 4,1,2,1,2
**输出:**4
示例 3 :
**输入:**nums = 1
**输出:**1
解题思路:
方法一:位运算
核心思路:异或运算
异或的性质:
| 性质 | 说明 |
|---|---|
a ^ a = 0 |
相同数异或为 0 |
a ^ 0 = a |
任何数异或 0 等于自身 |
| 交换律 | a ^ b = b ^ a |
| 结合律 | (a ^ b) ^ c = a ^ (b ^ c) |
观察:
把所有数异或起来:
-
出现两次的数异或后变成 0
-
只出现一次的数异或后保留下来
2 ^ 2 ^ 1 = 0 ^ 1 = 1
4 ^ 1 ^ 2 ^ 1 ^ 2 = 4 ^ (1^1) ^ (2^2) = 4 ^ 0 ^ 0 = 4
具体过程示例:
nums = [4,1,2,1,2]
4 ^ 1 = 5
5 ^ 2 = 7
7 ^ 1 = 6
6 ^ 2 = 4
结果: 4 ✅
代码实现:
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
int result = 0;
for (int num : nums) {
result ^= num;
}
return result;
}
};
复杂度分析:
| 维度 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 一次遍历 |
| 空间复杂度 | O(1) | 只用一个变量 |
关键细节:
1. 为什么异或能满足要求?
-
出现两次的数:
a ^ a = 0,互相抵消 -
只出现一次的数:
a ^ 0 = a,保留下来 -
异或满足交换律和结合律,顺序不影响结果
2. 如果出现三次呢?
异或就不行了,需要用位计数:统计每一位 1 的个数,对 3 取模。
137 题:只出现一次的数字 II(其余出现三次)
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
int result = 0;
for (int i = 0; i < 32; i++) {
int count = 0;
for (int num : nums) {
count += (num >> i) & 1;
}
if (count % 3 != 0) {
result |= (1 << i);
}
}
return result;
}
};
3. 如果出现两次的有两个呢?
260 题:只出现一次的数字 III(有两个只出现一次的数)
需要先用异或找到分组依据,再分组异或。
方法二:哈希表(O(n) 空间)
代码实现:
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
unordered_map<int, int> count;
for (int num : nums) count[num]++;
for (auto& [num, cnt] : count) {
if (cnt == 1) return num;
}
return -1;
}
};
复杂度:时间 O(n),空间 O(n)
缺点:不满足 O(1) 空间要求。
方法三:排序(O(n log n))
代码实现:
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size() - 1; i += 2) {
if (nums[i] != nums[i+1]) return nums[i];
}
return nums.back();
}
};
复杂度:时间 O(n log n),空间 O(1)
三种方法对比:
| 方法 | 时间复杂度 | 空间复杂度 | 推荐度 |
|---|---|---|---|
| 异或 | O(n) | O(1) | ⭐⭐⭐⭐⭐ |
| 哈希表 | O(n) | O(n) | ⭐⭐⭐ |
| 排序 | O(n log n) | O(1) | ⭐⭐ |
总结:
| 要点 | 说明 |
|---|---|
| 核心思想 | 异或:相同为 0,不同为 1 |
| 关键性质 | a ^ a = 0,a ^ 0 = a |
| 时间复杂度 | O(n) |
| 空间复杂度 | O(1) |