leetcode 面试题56

题目描述:

  一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是$O(n)$,空间复杂度是$O(1)$。

题解:

  如果数组里面只有一个数字出现了一次,其余出现了两次,一遍异或就可以将其找出来。对于两个只出现一次的数,我们考虑将其分组,使得:

  1. 两个只出现一次的数字在不同的组中;

  2. 相同的数字会被分到相同的组中。

  记两个只出现一次数字分别为$a$和$b$,那么所有数字异或的结果等于$a$和$b$异或的和,我们记为$x$。将$x$看作二进制$x_{k}x_{k-1}...x_{2}x{1}x{0}$,其中$x_{i} in {0,1}$。对于$x$二进制每一位而言,表示的是$a$和$b$这一位是否相同,那么只要以$x$二进制位上任意一个为1的位置作为判断点,如果该位为0就分为第一组,为1就分给第二组,这样就能达到我们想要的分组效果。这样做的可行性很好分析,首先两个只出现一次的数字在不同的组中这一点很容易满足,那么相同的数字是否会分到相同的组中?相同的数字某一位二进制的值一定是相同的,所以一定会分到相同的组中。

AC代码:

  

class Solution {
public:
    int del(int tmp)
    {
        int pos=0;
        while(tmp)
        {
            if(tmp%2 == 1) return pos;
            pos++;
            tmp/=2;
        }
        return -1;
    }
    vector<int> singleNumbers(vector<int>& nums) {
        int tmp = nums[0];
        int Len = nums.size();
        for(int i=1;i<Len;i++) tmp ^= nums[i];
        int flag_pos = del(tmp);
        int g1,g2;
        int flag1,flag2;
        flag1 = flag2 = 1;

        for(auto &num:nums)
        {
            if( ((num>>flag_pos)&1) == 1) 
            {
                if(flag1  == 1) 
                {
                    g1 = num;
                    flag1 = -1;
                }
                else g1 ^= num;
            }
            else
            {
                if(flag2 == 1) 
                {
                    g2 = num;
                    flag2 = -1;
                }
                else g2 ^= num;
            }
        }

        return {g1,g2};
    }
};
原文地址:https://www.cnblogs.com/z1141000271/p/12796615.html