# 136. 只出现一次的数字

力扣题目链接 (opens new window)

# 题目描述

给你一个 非空 整数数组 nums,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例 1:

输入:nums = [2,2,1]
输出:1
1
2

示例 2:

输入:nums = [4,1,2,1,2]
输出:4
1
2

示例 3:

输入:nums = [1]
输出:1
1
2

提示:

  • 1 <= nums.length <= 3 * 10⁴
  • -3 * 10⁴ <= nums[i] <= 3 * 10⁴
  • 除了某个元素只出现一次以外,其余每个元素均出现两次。

# 思路

这道题如果不考虑空间限制,很容易想到用哈希表统计每个元素出现次数,然后找出现一次的元素。

但题目要求只使用常量额外空间,哈希表就不行了,空间复杂度是 O(n)。

那怎么办呢?这就需要用到位运算中的异或(XOR)了。

# 异或运算的性质

异或运算有几个重要性质:

  1. 任何数和 0 异或,结果是它本身: a ^ 0 = a
  2. 任何数和它本身异或,结果是 0: a ^ a = 0
  3. 异或满足交换律和结合律: a ^ b ^ a = a ^ a ^ b = 0 ^ b = b

第三条性质是关键!

如果我们把数组中所有元素都异或起来,出现两次的元素会相互抵消变成 0,最后剩下的就是只出现一次的元素。

例如 [4,1,2,1,2]:

4 ^ 1 ^ 2 ^ 1 ^ 2
= 4 ^ (1 ^ 1) ^ (2 ^ 2)  // 交换律和结合律
= 4 ^ 0 ^ 0
= 4
1
2
3
4

这就是本题的最优解法:一次遍历,所有元素异或,时间O(n),空间O(1)。

# 模拟过程

以 nums = [4,1,2,1,2] 为例:

初始状态:

result = 0
1

遍历过程:

当前元素 异或操作 result (二进制) result (十进制)
4 0 ^ 4 0100 4
1 4 ^ 1 0101 5
2 5 ^ 2 0111 7
1 7 ^ 1 0110 6
2 6 ^ 2 0100 4

最终结果: 4

我们也可以按配对的方式理解:

4 ^ 1 ^ 2 ^ 1 ^ 2
= 4 ^ (1 ^ 1) ^ (2 ^ 2)
= 4 ^ 0 ^ 0
= 4
1
2
3
4

drawio 提示词: 画两张图说明异或抵消原理。第一张展示数组 [4,1,2,1,2],用相同颜色标注成对的元素(两个1用蓝色,两个2用绿色,4用红色单独标注),并在下方列出异或的三条性质。第二张展示异或的计算过程,用树状图或分组的形式表现 4 ^ (1^1) ^ (2^2) = 4 ^ 0 ^ 0 = 4 的化简过程,配对的元素用箭头指向 0。两张图画布统一,Logo 放左下角。

文件名:

  • 0136.single-number-01-pairing.drawio
  • 0136.single-number-02-xor-process.drawio

# 解题代码

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int result = 0;
        
        for (int num : nums) {
            result ^= num; // 所有元素异或
        }
        
        return result; // 出现两次的抵消,剩下只出现一次的
    }
};
1
2
3
4
5
6
7
8
9
10
11
12

# 复杂度分析

  • 时间复杂度:O(n),需要遍历一遍数组
  • 空间复杂度:O(1),只用了一个变量

# 其他语言

# Python3

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        result = 0
        
        for num in nums:
            result ^= num
        
        return result
1
2
3
4
5
6
7
8

# Java

class Solution {
    public int singleNumber(int[] nums) {
        int result = 0;
        
        for (int num : nums) {
            result ^= num;
        }
        
        return result;
    }
}
1
2
3
4
5
6
7
8
9
10
11

# Go

func singleNumber(nums []int) int {
    result := 0
    
    for _, num := range nums {
        result ^= num
    }
    
    return result
}
1
2
3
4
5
6
7
8
9

# JavaScript

var singleNumber = function(nums) {
    let result = 0;
    
    for (const num of nums) {
        result ^= num;
    }
    
    return result;
};
1
2
3
4
5
6
7
8
9

# 与代码随想录联系

这道题是位运算的经典应用,体现了异或运算在"配对抵消"场景中的妙用。

位运算在算法题中经常出现,很多看似复杂的问题,用位运算可以优雅地解决,并且通常能达到 O(1) 的空间复杂度。

如果录友们想系统学习位运算,可以关注代码随想录后续的位运算专题。常见的位运算技巧包括:异或找单独元素、与运算判断奇偶、移位运算做乘除等。

本题也可以用哈希表解决(用 set 记录出现过的元素,第二次出现就删除,最后剩下的就是答案),但空间复杂度是 O(n),不如异或运算优雅。

上次更新:: 10/25/2026, 10:24:40 PM

评论

验证登录状态...