一、题目描述
给你一个 非空整数数组 nums ,除了某个元素 只出现一次 以外,其余每个元素均 出现两次。请找出那个只出现了一次的元素。
要求:
-
时间复杂度 O(n)
-
空间复杂度 O(1)
示例 1
输入:nums = [2,2,1]
输出:1
示例 2
输入:nums = [4,1,2,1,2]
输出:4
示例 3
输入:nums = [1]
输出:1
提示
1 <= nums.length <= 3 * 10^4
-3 * 10^4 <= nums[i] <= 3 * 10^4
二、解题思路
本题核心特点:
-
只有一个数字出现一次
-
其他数字都出现两次
可以从三个方向解决:
1️⃣ 哈希表统计次数
2️⃣ 排序后成对查找
3️⃣ 位运算(最优解)
下面逐一介绍。
三、解法一:哈希表
思路
使用哈希表统计每个数字出现的次数:
-
遍历数组
-
统计每个数字出现次数
-
找到出现一次的数字
由于题目范围为:
-30000 ~ 30000
可以直接用 数组模拟哈希表。
C语言代码
#include <stdlib.h>
int singleNumber(int* nums, int numsSize) {
int offset = 30000;
int hash[60001] = {0};
for(int i = 0; i < numsSize; i++)
{
hash[nums[i] + offset]++;
}
for(int i = 0; i < 60001; i++)
{
if(hash[i] == 1)
return i - offset;
}
return 0;
}
复杂度分析
时间复杂度:O(n)
空间复杂度:O(n)
缺点:不满足题目 常量空间要求。
四、解法二:排序
思路
先排序,然后每两个元素检查一次:
1 1 2 2 4
↑
如果某个元素 和相邻元素不同,说明它只出现一次。
C语言代码
#include <stdlib.h>
int cmp(const void* a, const void* b)
{
return (*(int*)a - *(int*)b);
}
int singleNumber(int* nums, int numsSize) {
qsort(nums, numsSize, sizeof(int), cmp);
for(int i = 0; i < numsSize - 1; i += 2)
{
if(nums[i] != nums[i+1])
return nums[i];
}
return nums[numsSize - 1];
}
复杂度分析
时间复杂度:O(n log n)
空间复杂度:O(1)
缺点:排序导致时间复杂度不满足题目要求。
五、解法三:位运算(最优解)
核心思想
利用 异或 XOR 运算。
异或的三个重要性质:
a ^ a = 0
a ^ 0 = a
满足交换律和结合律
例如:
2 ^ 2 ^ 1 = (2 ^ 2) ^ 1 = 0 ^ 1 = 1
所有 成对出现的数字都会抵消,最后剩下的就是只出现一次的数字。
算法步骤
-
定义变量
res = 0 -
遍历数组
-
每个元素与
res做异或 -
最终
res即为答案
C语言代码
int singleNumber(int* nums, int numsSize) {
int res = 0;
for(int i = 0; i < numsSize; i++)
{
res ^= nums[i];
}
return res;
}
执行过程示例
输入:
[4,1,2,1,2]
计算过程:
res = 0
0 ^ 4 = 4
4 ^ 1 = 5
5 ^ 2 = 7
7 ^ 1 = 6
6 ^ 2 = 4
最终结果:
4
复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)
满足题目要求,是 最优解法。
六、总结
| 解法 | 时间复杂度 | 空间复杂度 | 推荐 |
|---|---|---|---|
| 哈希表 | O(n) | O(n) | ⭐ |
| 排序 | O(n log n) | O(1) | ⭐ |
| 位运算 | O(n) | O(1) | ⭐⭐⭐ |
最佳方案:位运算(XOR)
原因:
-
时间复杂度 O(n)
-
空间复杂度 O(1)
-
代码简洁
✅ 本题属于经典位运算题,也是面试高频题。