天天看点

数组中只出现一次的数字,时间复杂度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);

}

继续阅读