剑指Offer56-I.数组中数字出现的次数 C++

1、题目描述

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

2、VS2019上运行

Krahets方法(位运算)

#include 
#include 

using namespace std;

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int x = 0, y = 0, n = 0, m = 1;
        for (int num : nums)         // 1. 遍历异或
            n ^= num;

        while ((n & m) == 0)         // 2. 循环左移,计算 m
            m <<= 1;

        for (int num : nums) {       // 3. 遍历 nums 分组
            if (num & m) x ^= num;   // 4. 当 num & m != 0
            else y ^= num;          // 4. 当 num & m == 0
        }
        return vector<int> {x, y};  // 5. 返回出现一次的数字
    }
};

int main() {
    vector<int> nums = { 1, 2, 1, 3, 2, 5 };
    Solution solution;
    vector<int> result = solution.singleNumbers(nums);
    cout << "Single Numbers: " << result[0] << " and " << result[1] << endl;
    return 0;
}

Single Numbers: 3 and 5

3、解题思路

  • 1、遍历数组nums,将所有数字进行异或运算并保存在变量n中。
    nums中所有出现两次的数字进行异或运算,结果会相互抵消为0。
    只出现一次的两个数字,在异或运算中会保留下来。
  • 2、找到n中最低位的1,并将其保存在变量m中。
    初始时,m为1(二进制为 0001)。
    通过将m左移,每次左移一位,直到(n & m)不等于0,也就是找到n中最低位的1。
    这个步骤的目的是将两个只出现一次的数字区分到不同的分组。
  • 3、再次遍历数组nums,根据m的值将数字分为两组,并分别进行异或运算。
    如果数字在m位上为1,将其归为一组。
    如果数字在m位上为0,将其归为另一组。
    这样,只出现一次的两个数字就被分到了不同的组中。
  • 4、进行异或运算,得到两个只出现一次的数字。
    对每个分组中的数字进行异或运算,得到两个结果:x和y。
    x和y就是只出现一次的两个数字。
  • 5、将x和y放入一个新的vector中,并作为结果返回。

你可能感兴趣的:(剑指Offer刷题,c++,算法,leetcode,力扣)