136. 只出现一次的数字
LeetCode 1361 · 简单 · 技巧
题
非空整数数组里,除了一个元素只出现一次,其余每个都恰好出现两次,找出那个落单的。要求线性时间、常数额外空间。
例:nums = [4, 1, 2, 1, 2] → 4。
一句话
把所有数异或起来——出现两次的两两抵消成 0,结果就是落单的数。
关键技巧
异或的三条性质。 \(x \oplus x = 0\),\(x \oplus 0 = x\),异或满足交换律和结合律。所以不管顺序如何,\(\bigoplus \text{nums}\) 可以重排成「每对相同的数挨在一起」,每对变 0,只剩落单的那个。
为什么想到异或。 常数空间意味着不能计数、不能哈希;「成对出现」对应的就是一个能自我抵消的运算。加法也能抵消,但要知道「另一半」才能减——异或不需要。
负数也没问题。 Python 整数异或按补码语义进行,负数照常抵消。
解
class Solution:
def singleNumber(self, nums: List[int]) -> int:
acc = 0
for x in nums:
acc ^= x # 成对的互相抵消
return acc
时间 \(O(n)\),空间 \(O(1)\)。
延伸
- 其余出现三次(LeetCode 137):按位统计 1 的个数模 3,或用两个变量做状态机。
- 两个落单(LeetCode 260):全体异或得 \(a \oplus b\),取其最低位的 1 把数组分成两组,各组异或一次。
- 「抵消」同一个思想:169. 多数元素 的投票法是让不同的数两两抵消;287. 寻找重复数 也有按位统计的解法。
自测
-
LeetCode 136,2026-09-29 读。 ↩