1. 程式人生 > >資料結構面試題總結5——陣列:找出陣列中唯一一個出現一次的元素

資料結構面試題總結5——陣列:找出陣列中唯一一個出現一次的元素

問題描述:一個數組其中有一個元素出現了一次(奇次),其他元素都出現兩次(偶數次數),找出出現一次(奇次)的元素。

分析:碰到這種偶次奇次的問題,首先要想一下位運算中的異或。一個數異或本身為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 ;    
}