综合题

给定一个含 n(n≥1)个整数的数组, 请设计一个在时间上尽可能高效的算法, 找出数组中未出现的最小正整数。 例如,数组{-5, 3, 2, 3}中未出现的最小正整数是 1; 数组{1, 2, 3}中未出现的最小正整数是 4。 要求:

问答题

给出算法的基本设计思想。

【正确答案】

题目要求算法时间上尽可能高效, 因此采用空间换时间的办法。 分配一个用于标记的数组 B[n], 用来记录 A 中是否出现了 1~n 中的正整数, B[0]对应正整数 1, B[n-1]对应正整数 n, 初始化 B 中全部为 0。 由于 A 中含有 n 个整数, 因此可能返回的值是 1~n+1, 当 A 中 n 个数恰好为1~n 时返回 n+1。 当数组 A 中出现了小于等于 0 或者大于 n 的值时, 会导致 1~n 中出现空余位置,返回结果必然在 1~n 中, 因此对于 A 中出现了小于等于 0 或者大于 n 的值可以不采取任何操作。
经过以上分析可以得出算法流程: 从 A[0]开始遍历 A, 若 0<A[i]<=n, 则令 B[A[i]-1]=1; 否则不做操作。 对 A 遍历结束后, 开始遍历数组 B, 若能查找到第一个满足 B[i]==0 的下标 i, 返回i+1 即为结果, 此时说明 A 中未出现的最小正整数在 1~n 之间。 若 B[i]全部不为 0, 返回 i+1(跳出循环时 i=n, i+1 等于 n+1), 此时说明 A 中未出现的最小正整数是 n+1。

【答案解析】
问答题

根据设计思想, 采用 C 或 C++语言描述算法, 关键之处给出注释。

【正确答案】

int findMissMin(int A[] , int n)
{
   int i, *B;                                       //标记数组
   B=(int *) malloc(sizeof(int) *n) ; //分配空间
   memset(B, 0, sizeof(int) *n) ;      //赋初值为0
   for(i=0; i<n; i++)
         if(A[i] >0&&A[i] <=n)          //若A[i] 的值介于1~n, 则标记数组B
               B[A[i] -1] =1;
   for(i=0; i<n; i++)                       //扫描数组B, 找到目标值
         if (B[i] ==0) break;
   return i+1;                                 //返回结果
}

【答案解析】
问答题

说明你所设计算法的时间复杂度和空间复杂度。

【正确答案】

时间复杂度: 遍历 A 一次, 遍历 B 一次, 两次循环内操作步骤为 O(1)量级, 因此时间复杂度为 O(n)。 空间复杂度: 额外分配了 B[n], 空间复杂度为 O(n)。

【答案解析】