找數組中唯一重複的元素

1-1000放在含有1001個元素的數組中,只有唯一的一個元素值重複,其它均只出現一次.每個數組元素只能訪問一次,設計一個算法,將它找出來;不用輔助存儲空間。

(1)   方法一:(當N爲比較大時警惕溢出)

將1001個元素相加減去1,2,3,……1000數列的和,得到的差即爲重複的元素。

int  Find(int*   a)
	{  
		int   i;
		for  (i = 0;i<=1000;i++)    
			a[1000]   +=   a[i];    
		
		a[1000]   -=   (i*(i-1))/2;       //i的值爲1001  
		
		return   a[1000];
	}

(2)   方法二:

數組取值操作可以看做一個特殊的函數f:D→R,定義域爲下標值0~1000,值域爲1到1000.如果對任意一個數 i,我們把f(i)叫做它的後繼,i叫f(i)的前驅。0只有後繼沒有前驅,其他數字既有後繼也有前驅,重複的那個數字有兩個前驅,我們將利用這些特徵。

規律:從0開始畫一個箭頭指向它的後繼,從它的後繼繼續指向後繼的後繼,這樣,必然會有一個節點指向之前已經出現過的數,即爲重複的數。

 

利用下標與單元中所存儲的內容之間的特殊關係,進行遍歷訪問單元,一旦訪問過的單元賦予一個標記,利用標記作爲發現重複數字的關鍵。

int find2(int *a) {
		int index = 0;
		while(true){
			if(a[index] < 0 ) {
				break;
			}
			a[index] = 0 - a[index];
			index = 0 - a[index];
		}
		return a[index];
	}

(3)   方法三

同樣考慮下標與內容的關係,不過不用標記,而用兩個速度不同的過程來訪問。Slow每次前進一步,fast每次前進兩步。在有環結構中,它們總會相遇。

int find3(int *a) {
		int slow =0, fast = 0;
		while( true ) {
			slow = a[slow];
			fast = a[a[fast]];
			if(slow == fast){
				break;
			}
		}
		return a[slow];
	}

(4)   方法四:異或操作

數組a[N]中的N個數異或結果與1至N-1異或的結果再做異或,得到的值即爲所求。

  • 設重複數爲A,其餘N-2個數異或結果爲B。
  • N個數異或結果爲A^A^B
  • 1至N-1異或結果爲A^B
  • 由於異或滿足交換律和結合律,且X^X = 0 ,0^X = X;
  • 則有
  • (A^B)^(A^A^B)=A^B^B=A

int find4(int *a, int length) {
		int result = 0;
		for(int i = 1; i <= 1000; i++) {
			result ^= i;
		}
		for(int i=0; i<=1000; i++ ) {
			result ^=  a[i];
		}
		return result;
	}

摘自http://www.cnblogs.com/answeryi/archive/2012/09/24/2700529.html,部分算法有改動,其中第四個算法借鑑http://blog.csdn.net/imzoer/article/details/8013277

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