剑指 Offer 56 - I. 数组中数字出现的次数

发布时间 2023-04-09 01:08:59作者: lxy_cn

题目链接:剑指 Offer 56 - I. 数组中数字出现的次数

方法:位运算 + 分类

解题思路

异或运算:当两个相同的数异或时,结果为\(0\)
对于本题,假设答案为\(res1\)\(res2\),那么对数组中所有的数求异或时,其结果实际等于 \(res1\) ^ \(res2\);并且此结果中二进制位为1的位置就是\(res1\)\(res2\)对应的二进制位中不同位置,说明\(res1\)\(res2\)在该位的二进制位一个是\(0\)一个是\(1\)。那么我们可以根据其中某个不同的位作为基准,将该位为\(0\)的分为一类,为\(1\)的分为一类,对每一类求异或,就得到了两个答案。为了方便计算选取\(res1\) ^ \(res2\)结果中的最后一位\(1\)的位置为基准。

代码

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int x = 0;
        for (auto &num : nums) x ^= num; // 计算 res1 ^ res2
        int idx = 0;
        while (!(x & 1)) { // 找到最后一位1的位置(从右到左)
            x >>= 1;
            idx ++ ;
        }
        int res1 = 0, res2 = 0;
        for (auto &num : nums) { // 分类求异或
            if ((num >> idx) & 1) res1 ^= num;
            else res2 ^= num; 
        }
        return {res1, res2};
    }
};

复杂度分析

时间复杂度:\(O(n)\)
空间复杂度:\(O(1)\)