2023/10/15

175 阅读2分钟

137. 只出现一次的数字 II

算法掌握:

  • 位运算(异或 ^, 取反~,与运算&)
  • 常见的位运算操作:
    • 与运算(&):对两个操作数的每个对应比特位执行 AND 运算,只有当两个位都为 1 时,结果位才为 1。
    • 或运算(|):对两个操作数的每个对应比特位执行 OR 运算,只要其中一个位为 1,结果位就为 1。
    • 异或运算(^):对两个操作数的每个对应比特位执行 XOR 运算,当两个位不同时结果位为 1,否则为 0。
    • 取反运算(~):反转操作数的每个位,将 0 变为 1,将 1 变为 0。
    • 左移运算(<<):将操作数的比特位向左移动指定的位数,低位补 0。
    • 右移运算(>>):将操作数的比特位向右移动指定的位数,高位补符号位(负数补 1,正数补 0)。

解题思路:

本题如果不考虑 线性时间复杂度的算法且使用常数级空间来解决此问题的话, 直接用hash表存储判读即可,本题还是和 136. 只出现一次的数字 差不多的思路,可以先观看 leetcode每日一题 2023/10/14 这篇文章,不同的是判断的条件不一样,我们可以将一串数展开为2进制,相同得三个数的对应二进制位的数都是三倍,将数的每一位的个数进行判断即可

例如 [2, 2, 3, 2]

image.png

我们多尝试几组数据来验证 [3, 4, 4, 4, 5, 5, 5]

image.png

位运算性质

  • 异或运算:x ^ 0 = x, x ^ 1 = ~x (取反)
  • 与运算:x & 0 = 0 , x & 1 = x % 2 (取最低位)
  • 位移运算: x >> i = x / (i * 2), (x >> i) & 1 -> (取出第i位的数)
  • 或运算: for i -> 32: x |= (1 << i) (将每一位的值合并)

java code:

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        // int型是32位,将每一位取出计算
        for(int i = 0; i < 32; i++){
            int cnt = 0;
            for(int num : nums){
                cnt += (num >> i) & 1;
            }
            if(cnt % 3 > 0) res |= (1 << i);
        }
        return res;
    }
}

c++ code

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res = 0;
        for(int i = 0; i < 32; i++){
            int cnt = 0;
            for(int num : nums) cnt += (num >> i) & 1;
            if(cnt % 3) res |= (1 << i);
        }
        return res;
    }
};