取值爲[1,n-1]含n個元素的整數數組至少存在一個重複數,找出一個重複元素

1. 問題描述

取值爲[1,n-1]含n個元素的整數數組至少存在一個重複數,O(n)時間內找出其中任意一個重複數。如a[]={1,2,2,4,5,4},則2和4均是重複元素。


2. 解決方案

<單鏈表存在環> 第三種解決方案有很強的技巧性。“判斷單鏈表是否存在環”是一個非常經典的問題,同時單鏈表可以採用數組實現,此時每個元素值作爲next指針指向下一個元素。該題可以轉化爲“已知一個單鏈表中存在環,找出環的入口點”。

該題思路如下:將a[i]看做第i個元素的索引,即:a[i]->a[a[i]]->a[a[a[i]]]->a[a[a[a[i]]]]->….最終形成一個單鏈表,由於數組a中存在重複元素,則一定存在一個環,且環的入口元素即爲重複元素。

該題的關鍵在於,數組a的大小時n,而元素的範圍是[1,n-1],所以a[0]不會指向自己,進而不會陷入錯誤的自循環。如果元素的範圍中包含0,則該題不可直接採用該方法。

代碼如下:

int find_duplicated_integer2(int a[], int n) {
	int x, y;
	x = y = 0;
	do {
		x = a[a[x]]; //x一次走兩步
		y = a[y]; //y一次走一步
	} while(x != y); //找到環中的一個點
	x = 0;
	do {
		x = a[x];
		y = a[y];
	} while(x != y); //找到入口點
	return x;
}


以上參見http://www.jobcoding.com/datastructure-and-algorithm/array/one-unsorted-array/find-one-duplicated-integer/



一開始不明白爲什麼分這樣的兩趟進行,後來用數學式推導了一下是對的。

證明上述方法的正確性:

設環外、環上元素個數分別爲a,b。

進行第一次循環,初始狀態x=0,y=0。x,y從環外開始走,第a+1步進入環後必定在環上追趕而相遇,設相遇時y走了a+m步,則x走了2(a+m)步=a+(a+2m).

a+m,a+(a+2m)在環上同一位置(但並不一定是環的入口a+1),那麼兩者之差a+m是環上元素個數b的倍數,即a+m可被b整除,設a+m=nb.

進行第二次循環,初始狀態x=0,y=a+m。x從環外開始走,第a+1步到達環的入口;此時y到達a+m + a+1=a+nb+1,同樣也是環的入口。故兩者在環的入口相遇。

入口點元素即爲數組重複元素。


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