1. 程式人生 > >陣列中只出現一次的數字,時間複雜度O(n),空間複雜度O(1)的解法

陣列中只出現一次的數字,時間複雜度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);
}