《劍指offer》:[51]陣列中的重複數字

塵虛緣_KY發表於2016-06-28
題目:在一個長度為n的陣列裡所有數字都在0到n-1的範圍裡。陣列中某些數字是重複的,但是不知道有幾個數字重複了,也不知道每個數字重複幾次。請找出陣列中任意一個重複的數字。例如,如果輸入長度為7的陣列{2,3,1,0,2,5,3},那麼對應的輸出是重複的數字2或者3.
   分析:其實這個題因為它的限制太多,這樣是這個題失去了泛型,比如裡面的數字的範圍確定在0到n-1內,還有任意意對即可,不能對任意的陣列進行查重操作。下面先來看看這個問題怎麼解決吧!
方案一:時間複雜度為O(N*N)的順序掃描法。從第一個掃描到最後,依次進行第二個....一定能找出。
方案二:時間複雜度為O(N)+輔助空間O(N)的雜湊表。將每個數對映到雜湊表,掃描一遍能統計出所有數字出現的次數。然後掃描雜湊表能在O(1)的時間內得到該資料出現的次數。這樣便能找到重複的數字了。
方案三:時間複雜度為0(N),並且不要輔助空間。
思想是這樣的:順序掃描陣列的每個數字。當掃描到下標為i的數字時,比較該數字M是不是與下標i相等,如等,掃描下一個;如不等,再把它M和下標為M的數字相比較,如果相等,則找到一個返回;如果不等,則交換它們的值。

以陣列a[7]={2,3,1,0,2,5,3}為例,分析如下圖所示:


具體實現程式碼如下:
#include <iostream>
using namespace std;
int arr[7]={2,3,1,0,2,5,3};
void Swap(int &a,int &b)
{
	int temp;
	temp=a;
	a=b;
	b=temp;
}
bool duplicate(int array[],int length,int *duplication)
{
	if(array==NULL || length<0)
		return false;
	for(int i=0;i<length;i++)
	{
		if(array[i]<0 || array[i]>length-1 )
			return false;
	}
	for(int i=0;i<length;++i)
	{
		while(array[i]!=i)
		{
			if(array[i]==array[array[i]])
			{
				*duplication=array[i];
				return true;
			}
			Swap(array[i],array[array[i]]);
		}
	}
	return false;
}
int main()
{
	int result;
	bool res;
	res=duplicate(arr,7,&result);
	if(res)
		cout<<"重複的數是:"<<result<<endl;
	else
		cout<<"資料裡沒有重複的數!"<<endl;
	system("pause");
	return 0;
}

執行結果:


相關文章