神奇的位运算——力扣136.只出现一次的数字

力扣136.只出现一次的数字


【LeetCode题解】只出现一次的数字------Set解法和神奇的位运算

一、题目描述

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

请你找出那个只出现了一次的元素。

要求:

  • 时间复杂度为 O(n)
  • 空间复杂度为 O(1)

示例:

复制代码
输入:nums = [2,2,1]
输出:1

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

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

二、思路分析

这道题一看就让人想到用哈希结构来记录出现次数,但题目明确要求常量额外空间,所以我们要换个角度思考。

常见思路有两个:

  1. HashSet:存进去、出现两次就移除,最后剩下的就是答案。
  2. 位运算(异或 XOR):充分利用数学性质,优雅解决问题。

三、解法一:HashSet(直观思路)

我们先说最容易想到的办法。

  • 遍历数组,把数字加入 Set。
  • 如果已经存在,就移除它。
  • 遍历结束后,Set 里只会留下那个只出现一次的数。

代码

java 复制代码
import java.util.HashSet;

class Solution {
    public int singleNumber(int[] nums) {
        HashSet<Integer> set = new HashSet<>();
        for (int num : nums) {
            if (!set.add(num)) {
                set.remove(num);
            }
        }
        return set.iterator().next();
    }
}

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

虽然简单直观,但没有满足题目的空间要求。


四、解法二:位运算(异或 XOR)

这才是本题的核心与精华。

异或运算的性质

  1. a ^ a = 0
  2. a ^ 0 = a
  3. 交换律、结合律

结合这三个性质,可以看出:

  • 两个相同的数会互相抵消变成 0
  • 所有数异或一遍,剩下的就是只出现一次的那个数

举例

复制代码
nums = [4,1,2,1,2]

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

代码

java 复制代码
class Solution {
    public int singleNumber(int[] nums) {
        int ans = 0;
        for (int num : nums) {
            ans ^= num;
        }
        return ans;
    }
}

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
    这是题目的最优解。

五、方法对比

方法 时间复杂度 空间复杂度 思路
HashSet O(n) O(n) 简单直观,适合入门
XOR位运算 O(n) O(1) 优雅高效,面试必杀

六、进阶拓展

如果你觉得本题太简单,可以思考以下变种:

  1. 每个数字出现三次,只有一个数字出现一次

    • 可以用位运算统计每一位上 1 出现的次数,对 3 取模即可得到答案。
  2. 有两个数字各出现一次,其他数字出现两次

    • 先整体异或得到 x ^ y,再找出一个不为 0 的二进制位,将数组划分为两组,分别异或即可得到 xy

这些变种同样考验对位运算的理解,适合进一步练习。


七、总结

  • 如果不考虑空间复杂度,Set 是最容易想到的方案。
  • 如果追求最佳解,位运算 XOR 是唯一王道
  • 理解 XOR 的数学本质,可以帮助你秒杀一类经典问题。

相关推荐
Chan162 小时前
【 设计模式 | 结构型模式 代理模式 】
java·spring boot·后端·设计模式·intellij-idea
柯南二号2 小时前
【AI】【Java后端】RAG 实战示例:SpringBoot + 向量检索 + LLM 问答系统
java·人工智能·spring boot
Mr.Pascal2 小时前
后端直接返回错误信息的Map 和 抛出异常(异常机制)优劣势对比
java·springboot
自信的小螺丝钉2 小时前
Leetcode 155. 最小栈 辅助栈
leetcode·
吃着火锅x唱着歌2 小时前
LeetCode 3105.最长的严格递增或递减子数组
算法·leetcode·职场和发展
测试19983 小时前
Web自动化测试之测试用例流程设计
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
小卡皮巴拉3 小时前
【笔试强训】Day1
开发语言·数据结构·c++·算法
zcychong3 小时前
如何让A、B、C三个线程按严格顺序执行(附十一种解)?
java·面试
初圣魔门首席弟子3 小时前
switch缺少break出现bug
c++·算法·bug