LeetCode 137. 只出现一次的数字 II —— 位运算解法

题目描述

给你一个整数数组 nums ,除某个元素仅出现一次外,其余每个元素都恰出现三次。请你找出并返回那个只出现一次的元素。

你必须设计并实现 线性时间复杂度 且使用 常数级空间 的算法。

示例 1:

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

示例 2:

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

提示:

  • 1 <= nums.length <= 3 * 10^4

  • -2^31 <= nums[i] <= 2^31 - 1

  • 除某个元素仅出现一次外,其余每个元素都恰出现三次


解题思路

这道题是 位运算经典题 ,可以用 按位统计 的方法解决。

方法 1:按位统计(简单易理解)

  1. 统计每一位 1 的个数

    • int 有 32 位

    • 建一个 bit[32] 数组,表示每一位上 1 出现的次数

  2. 对 3 取模

    • 出现 3 次的数字在每一位上的 1 的个数是 3 的倍数

    • 只出现一次的数字会留下余数 1

  3. 还原结果

    • 将每一位余数为 1 的位置拼接起来,即为只出现一次的数字

C 语言实现

复制代码
int singleNumber(int* nums, int numsSize) {
    int bit[32] = {0};
    
    // 统计每一位1的个数
    for (int i = 0; i < numsSize; i++) {
        for (int j = 0; j < 32; j++) {
            bit[j] += (nums[i] >> j) & 1;
        }
    }

    int result = 0;

    // 取模3并还原结果
    for (int j = 0; j < 32; j++) {
        if (bit[j] % 3) {
            result |= (1u << j);   // 注意用 unsigned 避免符号位报错
        }
    }

    return result;
}

⚠️ 注意:

  • 1 << 31 可能会出现 未定义行为,因为 1 是 signed int

  • 1u << j 可以安全操作符号位


方法 2:状态机位运算(更优雅)

这个方法用 两个变量 onestwos 表示每一位出现次数的状态:

  • ones:该位出现过 1 次

  • twos:该位出现过 2 次

  • 当某位出现 3 次时,自动归零

核心公式:

复制代码
ones = (ones ^ num) & ~twos;
twos = (twos ^ num) & ~ones;

最终 ones 就是只出现一次的数字。

代码示例:

复制代码
int singleNumber(int* nums, int numsSize) {
    int ones = 0, twos = 0;
    for (int i = 0; i < numsSize; i++) {
        ones = (ones ^ nums[i]) & ~twos;
        twos = (twos ^ nums[i]) & ~ones;
    }
    return ones;
}
  • 时间复杂度:O(n)

  • 空间复杂度:O(1)


总结

  • 本题核心是 位运算 + 计数取模

  • 方法 1 用 32 位数组,易理解,但空间稍大

  • 方法 2 用 状态机位运算,常数空间,面试更加加分

  • 注意 符号位左移 的写法,要用 unsigned int 避免运行错误


💡 拓展思路

  • 如果数字出现次数不是 3,而是其他 k,按位统计仍然适用

  • 方法 2 的状态机也可以扩展到 k 次出现的情况

相关推荐
IronMurphy5 小时前
【算法四十三】279. 完全平方数
算法
墨染天姬5 小时前
【AI】Hermes的GEPA算法
人工智能·算法
mount_myj5 小时前
长长久久【C语言】
c语言
papership6 小时前
【入门级-数据结构-3、特殊树:完全二叉树的数组表示法】
数据结构·算法·链表
smj2302_796826526 小时前
解决leetcode第3911题.移除子数组元素后第k小偶数
数据结构·python·算法·leetcode
山甫aa6 小时前
差分数组 ----- 从零开始的数据结构
数据结构
早日退休!!!6 小时前
《数据结构选型指南》笔记
数据结构·数据库·oracle
Beginner x_u7 小时前
链表专题:JS 实现原理与高频算法题总结
javascript·算法·链表
丑八怪大丑7 小时前
Java数据结构与集合源码
数据结构
Legendary_0089 小时前
LDR6500:USB‑C DRP PD协议芯片技术详解与应用实践
c语言·开发语言