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 次出现的情况

相关推荐
阿豪只会阿巴2 小时前
咱这后续安排
c++·人工智能·算法·leetcode·ros2
像素猎人2 小时前
以数据结构之——树来体会深度优先搜索【dfs】和广度优先搜索【bfs】的妙用:学比特算法课的自用笔记
数据结构·c++·学习·dfs·bfs·深度优先搜索
爱编码的小八嘎2 小时前
C语言完美演绎3-14
c语言
逆境不可逃2 小时前
LeetCode 热题 100 之 215. 数组中的第K个最大元素 347. 前 K 个高频元素 295. 数据流的中位数
算法·leetcode·职场和发展
见叶之秋2 小时前
数据结构顺序表的使用
c语言
凤年徐2 小时前
优选算法——滑动窗口
c++·算法
DDzqss2 小时前
3.14打卡day35
算法
菜鸡儿齐2 小时前
HashMap源码学习
学习·哈希算法·散列表
WHS-_-20222 小时前
mCore: Achieving Sub-millisecond Scheduling for 5G MU-MIMO Systems
java·算法·5g