面試OR筆試22——數組中只出現一次的數字

1 題目及要求

1.1 題目描述

一個整數數組中除了兩個數字只出現一次之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)

例如輸入數組{2, 4, 3, 6, 3, 2,5, 5}只有46只出現了一次,其他的都出現了兩次,所以輸出是46

 

 

2 解答

2.1 題目分析

只有一個數字只出現一次時,用異或運算的性質:任何數和本身的異或得0。也就是說從頭到尾依次異或數組中的每個數字,那麼最終的結果剛好是那個只出現一次的數字,因爲那些成對出現兩次的數字全部在異或中抵消了。

因此對於兩個出現一次的數字,我們試着把原數組分成兩個子數組,使得每個數組只包含一個只出現一次的數字,而其他的數字都是成對地出現兩次。

首先,我們還是從頭到尾依次異或數組中的每個數字,那麼最終結果就是兩個只出現一次的數字的異或的結果。因爲其他數字都出現了兩次,在異或中全部抵消了。由於這兩個數字肯定不一樣,那麼異或的結果肯定不是0,也就是說起二進制表示中至少有一位是1。我們在結果中找到某一位爲1的位置(代碼實現的是最低位的1),記爲第bit位。然後我們以第bit位是不是1把原數組的數字分成兩組,第一組中的數字的bit位都爲1,第二組的爲0。那麼兩個相同的數字一定被分到同一組中,而兩個只出現一次的數字一定被分到不同的組中。這樣每個子數組都只有一個數字只出現一次,其他的都出現兩次。

 

2.2 代碼

#include <iostream>
using namespace std;

unsigned findFirstBit1(int n){
	unsigned bit = 0;
	for(bit=1;bit<sizeof(int)<<3 && !(n&1<<bit);++bit);
	return bit;
}

void findTwoNumbersAppearOnce(int *v, int n, int *num){
	if(!v || !num || n<2) return;
	int resXor = 0;
	for(int k1(0);k1<n;++k1) resXor ^= v[k1];
	int difBit = 1<<findFirstBit1(resXor);
	// int difBit = rexXor & (~resXor+1);	// 該句和更加簡潔
	num[0] = num[1] = 0;
	for(int k1(0);k1<n;++k1)
		if(v[k1]&difBit) num[0] ^= v[k1];
		else num[1] ^= v[k1];
}

int main(){
	int v[] = {2,4,3,6,3,2,5,5};
	int res[2];
	findTwoNumbersAppearOnce(v,8,res);
	cout << res[0] << ' ' << res[1] << endl;
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章