面試100 34找出數組中唯一出現一次的兩個數字
一問題描述
一個數組中,存在兩個只出現一次的數字,其余的數字均出現兩次。要求在時間復雜度o(n),空間復雜度為o(1)的情況下找出這兩個數字。
二 問題分析
此題實際考察了,對位操作的理解。首先進行簡化,考慮只有一個數組中,只存在出現了一次的一個數字,其余數字在數組中出現兩次,試
找出這個數字。
三 解決方案
首先 回憶 異或操作,任意數字與自身相異或,結果都為0.
還有一個重要的性質,即任何元素與0相異或,結果都為元素自身。
解決方案:
1 從數組的起始位置開始,對元素執行異或操作,則最后的結果,即為此只出現了一次的元素。
2 題目中,數組中存在兩個不同的元素,若是能仿造上述的解決方案,將兩個元素分別放置在兩個數組中,然后分別對每個數組進行異或操作,
則所求異或結果即為所求。
3 首先對原數組進行全部元素的異或,得到一個必然不為0的結果,然后判斷該結果的2進制數字中,為1的最低的一位。
然后根據此位是否為1 ,可以把原數組分為兩組。則兩個不同的元素,必然分別在這兩個數組中。
4 然后對兩個數組,進行異或操作,即可得到所求。
四 代碼示例
#include <iostream>
using namespace std ;
const int N = 10 ;
int getSingle(int * a) //獲取全部元素的異或結果

{
if(!a)
return -1;
int sum = a[0] ;
for(int i = 1; i < N; i++)
sum ^= a[i] ;
return sum ;
}
int getTwo(int * a ,int & one , int & two , int sum) //求數組中兩個不同的元素

{
unsigned int flag = 1;
while(flag) //求異或結果,最低的為1的二進制位,根據此位是否為1,將元素分為兩組,兩個不同的元素,在此位必然,一個為1,一個為0

{
if(flag&sum)
break;
flag = flag << 1 ;
}
//下面將flag與每個元素相求與,根絕結果是否為1,將其化為兩個數組
//分別計算每個數組的異或結果,并將結果,存儲分別存儲在one和two中。
one = two = 0 ;//0與任何數異或都為其自身,所以初始化的時候,應該初始化為0
for(int i = 0 ; i < N ;i++ )

{
if(a[i] & flag)

{
one ^= a[i] ;
}
else

{
two ^= a[i] ;
}
}
}
int main()

{

int a[N] =
{3 , 5 ,8 , 8 , 5 , 3 ,1 ,4 ,4,10} ;
int single = getSingle(a) ;
int one = 0 ;
int two = 0;
getTwo(a ,one , two ,single) ;
cout<<single<<" "<<one<<" "<<two<<endl ;
system("pause") ;
return 0 ;
}