数组中只出现一次的数字,时间复杂度O(n),空间复杂度O(1)的解法

题目:一个整型数组里除了两个数组外,其他的数字都出现了两次,要找出这两个数字。

     异或运算有一个性质:任何数异或它自己,结果都是0;这样如果题目变成只有一个数字只出现一次,其他数字均出现两次,这样我们从头到尾异或数组中的每一个数字,那么最终的结果就是只出现一次的数字。

    如果可以把数组中的数字分成两个子数组,每个数组里面包含一个只出现一次的数字,其他的数字都出现两次,这样按照上面的方法就可以分别求出只出现一次的数字了。首先,我们从头到尾异或数组中的每一个数字,那么得到的结果将是这两个只出现了一次的数字异或后的结果(因为其他出现了两次的数字都在异或中抵消了)。由于这两个数字不相同,所以它们的异或结果的二进制表示中至少有一位是1.我们先找到第一个为1的位的位置,记为第n位。然后我们以第n位是否为1,把原数组分成两个子数组,第一个数组中每个数的第n位都为1,第二个数组中的每个数的第n位都为0,因为两个相同的数字的任意一位都是相同的,所以相同的数肯定分在同一组,这样我们就实现了划分子数组的效果。

参考代码如下:

 #include<iostream>
#include<cstdio>
using namespace std;

bool Is1(int n,unsigned int bit)
{
    n=n>>bit;
    return (n&1);
}

unsigned int FindFirstBit1(int n)
{
    int bit=0;
    while((n&1)==0&&bit<8*sizeof(int))
    {
        n=n>>1;
        bit++;
    }
    return bit;
}

void FindNums(int data[],int len,int &num1,int &num2)
{
    if(data==NULL||len<2)
        return;
    int ans=0;
    for(int i=0;i<len;i++)
        ans=ans^data[i];
    unsigned int bit=FindFirstBit1(ans);
    for(int i=0;i<len;i++)
    {
        if(Is1(data[i],bit))
            num1=num1^data[i];
        else
            num2=num2^data[i];
    }
}

int main()
{
    int num1=0,num2=0;
    int data[100];
    int len;
    scanf(“%d”,&len);
    for(int i=0;i<len;i++)
       scanf(“%d”,&data[i]);
    FindNums(data,len,num1,num2);
    printf(“%d %d”,num1,num2);
}

点赞