資料結構面試題總結5——陣列:找出陣列中唯一一個出現一次的元素
阿新 • • 發佈:2019-01-24
問題描述:一個數組其中有一個元素出現了一次(奇次),其他元素都出現兩次(偶數次數),找出出現一次(奇次)的元素。
分析:碰到這種偶次奇次的問題,首先要想一下位運算中的異或。一個數異或本身為0,一個數異或0不變。a ^ a = 0, a ^ 0 = a。
這個題中,我們可以把所有的數一起求異或,那剩下的肯定就是出現一次的元素了。
int FindOnly(int *a, int n)
{
int onlyNum = a[0];
for(int i = 1; i < n; i++)
{
onlyNum = onlyNum ^ a[i];
}
return onlyNum;
}
問題變種:一個數組其中有兩個元素出現了一次(奇次),其他元素都出現兩次(偶數次數),找出出現一次(奇次)的元素。
此篇帖子裡有詳細描述,我並沒有找到原文,他也是轉的:http://blog.csdn.net/wangwh485/article/details/6715357
分析:因為有兩個元素了,他倆異或運算後的結果根本無法分辨出是哪兩個數,但是他倆異或的結果卻可以讓我們把他倆分開。
我們根據這個結果的最後為1的位,來把原陣列分成兩個陣列(此位為0的一組,此位為1的一組,這樣兩個出現一次(奇次)就被分到兩個陣列中了),再分別對這兩個陣列用第一個問題的方法。
我這裡就直接引用上面帖子中的程式碼了:
int getSingle(int *a, int n) //獲取全部元素的異或結果 { if(!a) return -1; int sum = a[0] ; for(int i = 1; i < n; i++) sum ^= a[i] ; return sum ; } void getTwo(int *a ,int & one, int & two, int sum, int n) //求陣列中兩個不同的元素 { 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[] = {3 , 5 ,8 , 8 , 5 , 3 ,1 ,4 ,4,10} ; int single = getSingle(a,10) ; int one = 0 ; int two = 0; getTwo(a ,one , two ,single,10) ; cout<<single<<" "<<one<<" "<<two<<endl ; system("pause") ; return 0 ; }