剑指offer55_数组中只出现一次的两个数字

数组中只出现一次的两个数字


一个整型数组里除了两个数字之外,其他的数字都出现了两次。

请写程序找出这两个只出现一次的数字。

你可以假设这两个数字一定存在。

数据范围

数组长度 [1,1000][1,1000][1,1000]

样例
输入:[1,2,3,3,4,4]

输出:[1,2]

算法思路

这个题挺好,不是很难但也颇受启发。利用异或运算的性质:

  1. 异或性质
    • a ^ a = 0(相同数字异或结果为0)
    • a ^ 0 = a(任何数字与0异或结果为其本身)
    • 异或运算满足交换律和结合律。
  2. 分组异或
    • 首先对所有数字进行异或,最终结果为两个目标数字的异或值 sum = x ^ y
    • 找到 sum 的二进制表示中任意一个为1的位(说明 xy 在该位上不同)。
    • 根据该位将数组分为两组,分别进行异或,最终得到两个目标数字。
时间复杂度
  • O(n):遍历数组两次,每次都是线性时间。
空间复杂度
  • O(1):仅使用了常数级别的额外空间(几个变量)。
class Solution {
public:
    vector<int> findNumsAppearOnce(vector<int>& nums) {
        int sum = 0, k = 0; // sum 是所有数的异或结果,k 用于找到不同的二进制位
        
        // 第一次遍历:计算所有数的异或结果 sum = x ^ y
        for (auto x : nums) sum ^= x;
        
        // 找到 sum 中第一个为1的位(说明 x 和 y 在这一位上不同)
        while (!(sum >> k & 1)) k++;
        
        int m = 0; // 用于存储分组后的异或结果
        // 第二次遍历:根据第k位是否为1,将数组分为两组,分别异或
        for (auto x : nums) {
            if (x >> k & 1) // 如果第k位是1,则异或到 m
                m ^= x;
        }
        
        // 返回两个数字:m 和 sum ^ m(因为 sum = x ^ y)
        return {m, sum ^ m};
    }
};

你可能感兴趣的:(算法,算法)