【2018年408统考真题】题目:给定一个含n(n≥1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。例如,数组{-5, 3, 2, 3}中未出现的最小正整数是1;数组{1, 2, 3}中未出现的最小正整数是4。
思路0:暴力查找,从正整数1开始查找
代码实现:
int FindMissMin(int A[], int n){
bool flag;
for(int i = 1; i < n + 1; i++){
flag = false;
for (int j = 0; j < n; ++j)
if(A[j] == i){
flag = true;
break;
}
if(flag == false) return i;
}
return n + 1;
}
思路1:先排序,再从1开始比对,考察排序算法(其中,基数排序算法最优:O(n))
思路2:要求在时间上尽可能高效,因此采用空间换时间的办法,因此,我们可以先创建一个大小为n的辅助数组b,用来记录原数组a中是否出现了1-n中的正整数,b[0]对应正整数1,b[n-1]对应正整数n,并初始化数组b中的元素全为。当数组a中出现了大于n或者小于1的整数时,会导致1-n中出现空余位置,返回的结果必然在1-n中,故我们可以不采取任何操作。于是,遍历数组a,若当前元素a[i]为不大于n的正整数,则在辅助数组下标为a[i]-1的位置上加一进行标记,最后我们的辅助数组即可统计得到原数组中每个不大于n的正整数出现的次数,接着我们再遍历辅助数组b,一旦遍历到当前元素值b[i]为0的时停止遍历,则当前下标+1即i+1为原数组a中未出现的最小整数,若正常退出循环时,则说明数组b中不存在值为0的元素,此时i=n,原数组a中未出现的最小整数则为n+1
代码实现:
int FindMissMin(int a[],int n) {
int i,*b; //标记数组
b=(int*)malloc(sizeof(int)*n); //分配空间
for(i=0;i<n;i++) //赋初值0
b[i]=0;
for(i=0;i<n;i++)
if(a[i]>0&&a[i]<=n)
b[a[i]-1]=1; //若a[i]介于1-n,则标记数组b
for(i=0;i<n;i++)
if(b[i]==0) break;
return i+1;
}
时间复杂度:先后遍历大小为n的数组a,b,故时间复杂度为O(n)
空间复杂度:额外分配了大小为n的数组b,故空间复杂度为O(n)