题目
分析给定一个数组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;
}