LeetCode 136简单位运算 · 异或
只出现一次的数字 图解题解
这道题到底在问什么
数组中只有一个数出现一次,其它都出现两次,找出那个数。
- nums
- [4,1,2,1,2]
- 输出
- 4
最优解:一步一步想明白
- 3关键不是背模板,而是看懂为什么这题适合位运算 · 异或。
- 4异或性质:x^x=0(相同抵消)、x^0=x。把所有数异或起来,成对的全消失,只剩出现一次的。ans 初始 0。
- 5ans = 0 ^ 4 = 4。
- 6ans = 4 ^ 1 = 5(暂时混进 1)。
- 7ans = 5 ^ 2 = 7(再混进 2)。
- 8关键帧:又遇到 1 → 两个 1 异或 = 0,自动抵消。ans 从 7 回到 6——别慌,看似变小其实是成对数字在互相消掉。
- 9又遇到 2 → 两个 2 也抵消。ans 回到 4。成对的都没了。
- 10扫完,剩下唯一没被抵消的 4 就是答案。和顺序无关,O(1) 空间。
- 13把这句话记住,下次遇到同类题,就能更快选出方向。
- 18把这题练到能复述后,再去同类题里迁移:先复用状态定义,再调整边界条件。
⚠️ 容易写错的地方
✗ 错:用计数表也能做但多 O(n) 空间
✓ 对:用异或让成对数字自动抵消
这题特意卡常数空间
✗ 错:以为只对正数有效
✓ 对:异或对负数(补码)同样成立
异或是逐位操作,与正负无关,含负数照样成对抵消。
✗ 错:ans 初值设成 nums[0]
✓ 对:初值设 0(异或单位元)
0^x=x,从 0 开始最干净;设别的值会污染结果。
完整代码(Python / C++ / Java)
Python
class Solution:
def singleNumber(self, nums):
ans = 0
for x in nums:
ans ^= x
return ansC++
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans = 0;
for (int x : nums) ans ^= x;
return ans;
}
};Java
class Solution {
public int singleNumber(int[] nums) {
int ans = 0;
for (int x : nums) ans ^= x;
return ans;
}
}套路模板 · 位运算 · 异或
# 位运算 · 异或 通用检查表
# 1. 定义状态/指针/容器
# 2. 每轮只做一个清晰动作
# 3. 更新答案并处理边界class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans = 0;
for (int x : nums) ans ^= x;
return ans;
}
};class Solution {
public int singleNumber(int[] nums) {
int ans = 0;
for (int x : nums) ans ^= x;
return ans;
}
}复杂度
时间复杂度
O(n)
一次遍历 n 个数,每个一次异或
空间复杂度
O(1)
只用 1 个整型变量 ans
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 只出现一次的数字 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
异或解法用了哪几条性质?+
x^x=0(自反)、x^0=x(单位元)、交换结合律(任意配对)。全体异或后成对消失、剩唯一数。
若是「出现三次、一个一次」(LC137)?+
异或不行,要按位统计每位 1 的个数 %3,或用两个变量模拟三进制状态机。
复杂度?+
O(n) 一次遍历、O(1) 空间。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。