演算法學習-第一個缺失的正整數

HelloNiGeSB發表於2016-12-05

題目

給定一個陣列A[0...N-1],找到從1開始,第一個不再陣列中的正整數。

如3,5,1,2,-3,7,14,8輸出4。

分析

解法很多,如下:

1、可以暴力求解,從1遍歷到n,每次和陣列對比,找到第一個不在陣列中的,時間複雜度為O(N2)

2、可以優化一下演算法,先排序在進行2分查詢,時間複雜度為N*log(N)。

3、因為第一個缺失的正整數肯定小於等於N+1,所以可以申請N個空間,然後遍歷原陣列,將大於0,小於n的數在新申請的空間中對應的位置做標記,最後遍歷申請的空間,找到第一個不在申請空間中的資料,時間複雜度是O(N),空間複雜度是O(N)

4、將找到的元素放到正確位置上,如果最終發現某個元素一直沒有找到,則該元素即為所求。迴圈不變式:如果某命題初始為真,且每次更改後仍然保持該命題為真,則若干次更改後該命題仍然為真。

假定前i-1個數已經找到,並且一次存放在A[1,2,...,i-1]中,繼續考察A[i]:

若A[i]<i且A[i]>=1,則A[i]在A[1,2,...,i-1]中已經出現過,可以直接丟棄。若A[i]為負,則更應該丟棄它。

若A[i]>i且A[i]<=N,則A[i]應該置於後面的位置,即將A[A[i]]和A[i]交換。若A[i]>N,由於缺失資料>=N,則A[i]丟棄。若A[A[i]]=A[i],顯然不比交換,直接丟棄A[i]即可。

若A[i]=i,則A[i]位於正確的位置上,則i加1,迴圈不變式擴大,繼續比較後面的元素。

演算法描述:

若A[i]=i,i加1,繼續比較後面的元素。

若A[i]<i或A[i]>N或A[A[i]]=A[i],丟棄A[i]

若A[i]>i,則將A[A[i]]和A[i]交換。

丟棄A[i]即將A[N]賦值給A[i],然後N減1.

下面給出第四種方法的程式碼

int FirstMissNumber(int* a, int size)
{
	a--;  // 從1開始
	int i = 1;
	while (i <= size)
	{
		if (a[i] == 1)
		{
			i++;
		}
		else if ((a[i] < i) || (a[i] > size) || (a[i] == a[a[i]]))
		{
			a[i] = a[size];
			size--;
		}
		else
		{
			int ntmp = a[a[i]];
			a[a[i]] = a[i];
			a[i] = ntmp;
		}
	}
	return i;
}


相關文章