【2018统考真题】
给定一个含n(n>=1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。 例如,数组{-5,3,2,3}中未出现的最小正整数是1;数组 {1,2,3}中未出现的最小正整数是4。
要求:
- 给出算法的基本设计思想。
- 根据设计思想,采用C或C++语言描述算法,关键之处给出注释。
- 说明你所设计算法的时间复杂度和空间复杂度。
思路
定义一个数组b,并赋值为0,将数组a中出现的>0且<n+1的值在数组b中标记=1,最后循环数组b,若值等于0,则其下标为最小值。
具体步骤
-
输入数组,编写一个求数组中未出现的最小正整数的值的函数,并返回最小值,输出。
-
求最小正整数的值的函数,返回值为int类型。传入的参数为数组a和数组的大小n。
-
定义一个数组b(范围是1~n+1),存放数组a出现的过的值的标记。
-
循环数组a,判断其是否大于0且小于等于n+1,若相等则将其值在数组b中赋值为1,以做标记。
-
循环数组b,判断值是否为0,若是,则将下标赋值给ans并返回。注意b的下标是从1开始,1~n+1。
具体实现
#include<bits/stdc++.h>
using namespace std;
//求最小正整数的方法,传参为输入的数组和数组大小n,下标为1~n
int FindMin(int a[],int n){
int b[n+2]={0}; //存放a[i]在范围的元素的标记值,下标为1~n+1
int ans=1; //定义最小整数
for(int j=1; j<n+1; j++){ //a数组只能从1开始,因为传入的数组就是从1开始的!!!
if(a[j]>0 && a[j]<=n+1)
b[a[j]]=1;
}
for(int j=1; j<n+2; j++){
if(b[j]==0){
ans=j; //第一个值为0的下标即为最小值
break;
}
}
return ans;
}
int main(){
int a[100],i=1; //i从1开始,所以数组中的整数个数为i个
while(cin>>a[i]){
if(cin.get()=='\n') break; //如果换行,跳出循环,即结束输入
else i++; //不换行,则继续输入,i继续+1
}
int ans = FindMin(a,i); //调用函数,返回最小正整数
cout<<ans;
return 0;
}
时空复杂度
-
时间复杂度:O(n)
-
空间复杂度:O(n)
小结
注意,在用数组做参数进行传递时,如果传递之前数组下标是从1开始的,那么传入后,数组下标依然要从1开始遍历,不能从0!!!