在问 · 算法题解

136. 只出现一次的数字

简单技巧异或抵消力扣原题 ↗

题目描述

输入一个非空整数数组 nums。其中恰有一个值只出现一次,其他每个值都恰好出现两次。

返回那个只出现一次的值。

算法需要线性时间,并且只使用常数级的额外空间。

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

解释:2 出现两次,1 只出现一次。

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

解释:1 和 2 各出现两次,只有 4 出现一次。

示例 3
输入:nums = [1]
输出:1

数据范围

  • 1 <= nums.length <= 3 * 10^4
  • -3 * 10^4 <= nums[i] <= 3 * 10^4
  • 除一个值只出现一次外,其余值都恰好出现两次。

解题思路:异或抵消

利用异或满足交换律、结合律且 x^x=0、x^0=x,遍历累计即可。

为什么正确

累计值等于已扫描元素的异或结果,成对元素会互相抵消。

复杂度分析

时间 O(n),空间 O(1)。

易错点

异或只适用于每个重复元素恰好出现两次的约束,不能替代一般频次统计。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

from typing import List

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        value = 0
        for num in nums:
            value ^= num
        return value

载入编辑器,自己跑一遍 →

其他解法

异或法空间 O(1),是进阶要求的答案;哈希法更易想到,但要 O(n) 空间。

解法 2:哈希集合 时间 O(n),空间 O(n)

遍历数组,用哈希集合记录出现过奇数次的数。第一次遇到就加入,第二次遇到就删除。遍历结束后集合里只剩下那个只出现一次的数。

思路直观,不依赖位运算性质。需要 O(n) 额外空间,不满足题目的常数空间进阶要求。

from typing import List

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        seen = set()
        for num in nums:
            if num in seen:
                seen.remove(num)
            else:
                seen.add(num)
        return seen.pop()

技巧 专题的其他题目

查看 技巧 全部题目 →