LC136 只出现一次的数字¶
简单通过率 77%python3核心代码模式技巧样例通过牛客 AC位运算数组
讲解章节:位运算
一句话
全体异或,成对的自相抵消,剩下的就是答案。
解题思路¶
这题考什么¶
异或(XOR,按位比较,两位不同得 1、相同得 0,Python 里写作 ^)有三条性质, 合起来正好把这题解掉:
题目保证除一个数外其余每个数恰好出现两次。把整个数组从头异或到尾, 由交换律可以随意重排成「配对相邻」的形式:
每一对都抵消成 0,只剩下那个落单的数。不需要知道谁和谁配对, 也不需要额外记录任何状态——这正是位运算最典型的用法。 位运算的系统讲法见 位运算。
「用哈希表计数」或「排序后看相邻」都能得到正确答案,但前者要 O(n) 额外空间, 后者要 O(n log n) 时间,都不满足题面「线性时间 + 常量空间」的硬性要求。
数据规模与复杂度¶
1 <= nums.length <= 3e4,-3e4 <= nums[i] <= 3e4。 时间 O(n),一趟扫描;额外空间 O(1),只有一个累加变量。 注意值域含负数,异或必须在能表示负数的整数上做——Python 的 int 是任意精度且按二进制补码语义实现位运算,(-5) ^ (-5) 照样是 0, 所以负数不需要任何特殊处理。
坑在哪¶
- 累加变量的初值只能是 0。0 是异或的单位元,
0 ^ nums[0]恰好等于 nums[0]。若初始化成 nums[0] 再从下标 0 开始异或,第一个数会被算两遍而抵消掉; 若初始化成 1 之类的非零值,答案会整体被那个值污染。 - 这题只对「其余元素恰好出现两次」成立。若某个数出现三次,异或后剩的是它本身 而不是 0,结论立刻失效——那属于 LC137 一类的问题,要按位统计出现次数模 3。
- 别用
sum(nums) - 2 * sum(set(nums))之类的求和技巧代替:结论虽也成立, 但要建集合,额外空间是 O(n),违背题面的常量空间要求。 - 异或运算符是
^,不是 Python 里的幂运算**,也不是逻辑或。写错不会报错, 只会静悄悄算出别的东西。 - 严格比对:落单的数唯一,没有多解。
样例复核¶
nums = [4, 1, 2, 1, 2],逐步异或:
结果 4,与题面一致。按交换律重排即 4 ^ (1 ^ 1) ^ (2 ^ 2) = 4 ^ 0 ^ 0 = 4, 中间那些看似无规律的 5、7、6 只是配对尚未凑齐时的中间态。
参考实现¶
| solutions/leetcode/LC136/sol.py | |
|---|---|
[:octicons-arrow-left-16: LC131](LC131.md) [LC138 :octicons-arrow-right-16:](LC138.md)