137. 只出现一次的数字 II

137. 只出现一次的数字 II

✨核心逻辑

本题采用 按位统计 + 模 3 还原(位运算) 的策略:

  1. 统计每一位:由于其他数字都出现了 3 次,它们在二进制表示下,每一个比特位 1 的个数总和必定是 3 的倍数。
  2. 取模剥离:我们遍历整数的 32 位,统计数组中所有元素在某一位上 1 出现的总次数。
  3. 还原结果:将统计的个数对 3 取余(count % 3)。如果结果等于 1,说明那个“只出现一次”的数字在这个二进制位上也是 1。通过按位或运算 (|=) 将这一位还原到答案中。

🔥代码实现(含详细变量注释)

class Solution {
    public int singleNumber(int[] nums) {
        // ans:用于记录并最终返回那个只出现了一次的数字结果
        int ans = 0;
        
        // i:遍历整数的 32 个二进制位(从低位 0 到高位 31)
        for (int i = 0; i < 32; i++) {
            // count:用于统计数组中所有元素,在第 i 位上,二进制值为 1 的出现次数
            int count = 0;
            
            // num:遍历数组中的每一个元素
            for (int num : nums) {
                // 判断当前数字 num 的第 i 位是否为 1,如果是,则 count 加 1
                if (((num >> i) & 1) == 1) {
                    count++;
                }
            }
            
            // 如果统计出的第 i 位的总个数,对 3 取余等于 1
            // 说明出现一次的数字在这一位上也是 1
            if (count % 3 == 1) {
                // 将二进制第 i 位设置为 1,并合并进 ans 结果中
                ans |= (1 << i);
            }
        }
        
        // 返回还原出来的只出现一次的数字
        return ans;
    }
}

  • ⏱️复杂度分析
    • 时间复杂度:O(32 * N) = O(N),其中 N 是数组的长度。外层循环固定执行 32 次,内部遍历数组的时间为 O(N),常数 32 可忽略,整体为线性时间复杂度。

    • 空间复杂度:O(1),只使用了 ans、i、count 和循环变量 num 等常数个额外整型变量。

🔍总结一下:

用二进制的思想去写题,遍历32次,内层对每个数组的元素进行二进制表达式中末尾元素1的计算,也就是统计1的次数,如果 %3 ==1

说明当前位就,对1进行移动 i 位即可,是1则ez