Skip to content

【位运算】数组中出现的次数为一的数字

有一个数字只出现了一次

其余数字都出现了两次,找到这个数,要求\(O(1)\)空间复杂度。

全部异或一遍即可。

有两个数字只出现了一次

其余数字都出现了两次,找到这个数,要求\(O(1)\)空间复杂度。

分组异或。考虑这两个数为a, b,我们可以得到a ^ b,然后任选一个为一bit作为分组依据。

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int a = 0, b = 0, i = 0;
        for (int x: nums) a ^= x;
        while ((a & (1<<i)) == 0) i++;
        a = 0;
        for (int x: nums) {
            if (x & (1<<i)) a ^= x;
            else b ^= x;
        }
        return {a, b};
    }
};

有一个数字只出现了一次,其余数字都出现了三次

要求\(O(1)\)空间复杂度。

计算每个bit出现的次数,取模即可。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int v[32] = {0};
        for (int x: nums) {
            for (int i = 0; i < 32; i++) {
                if (x & (1 << i)) v[i] = (v[i] + 1) % 3;
            }
        }
        int ans = 0;
        for (int i = 0; i < 32; i++) {
            if (v[i]) ans |=(1 << i);
        }
        return ans;
    }
};

高级做法:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int c1 = 0, c2 = 0;
        for (int x: nums) {
            c1 = c1 ^ x & ~c2;
            c2 = c2 ^ x & ~c1;
        }
        return c1;
    }
};

有一个数字只出现了一次,其余数字都出现了m次

要求\(O(1)\)空间复杂度。

第二种方法通解。

class Solution {
public:
    int singleNumber(vector<int>& nums, int m) {
        int v[32] = {0};
        for (int x: nums) {
            for (int i = 0; i < 32; i++) {
                if (x & (1 << i)) v[i] = (v[i] + 1) % m;
            }
        }
        int ans = 0;
        for (int i = 0; i < 32; i++) {
            if (v[i]) ans |=(1 << i);
        }
        return ans;
    }
};