【408DS算法题】基础008-18年真题_数组中为出现的最小正整数

真题题目

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

  1. 给出算法的基本设计思想。
  2. 根据设计思想,采用C、C++或 Java 语言描述算法,关键之处给出注释。
  3. 说明你所设计算法的时间复杂度和空间复杂度。

(本文重点关注算法实现思路,不含具体答题表述)

分析实现

通常“未出现xxx”一类的题目,我们会想到先记录下数组中出现的元素信息,然后进行分析。
对于本题,要求返回第一个未出现的正整数,又因为数组元素个数为n,故最小未出现正整数一定在区间 [ 1 , n + 1 ] [1, n+1] [1,n+1] 内。因此,可建立一个大小为n的布尔数组存储正整数 [ 1 , n ] [1, n] [1,n]的出现情况,倘若 [ 1 , n ] [1, n] [1,n]均出现,则最小未出现正整数为n+1。(实际上也可以直接建立n+1的布尔数组存储 [ 1 , n + 1 ] [1, n+1] [1,n+1]的出现情况)

具体实现如下:(为了简洁,这里新建了n+1的布尔数组,使得a[i]可以直接表示元素i的出现情况)

# include<vector>

int minAbsent(vector<int>& a){
	int n=a.size();
	// 布尔数组, 若a中有i, 则has[i]=true
	vector<bool> has(n+1, 0);
	for(auto &x:a){
		if(x>0 && x<=n){
			has[x]=1;
		}
	}
	// 扫描has数组, 找到第一个未出现正整数
	for(int i=1; i<=n; i++){
		if(!has[i]){
			return i;
		}
	}
	// [1,n]均出现, 返回n+1
	return n+1;
}

总结

以上就是运用一个数组记录元素出现情况,然后扫描该数组来求出数组中未出现的最小正整数的算法。

此外,抱着学习的态度(个人认为并不会出现这样的考题),如果对原题目进行两点修改:

  1. 数组内元素递增
  2. 空间复杂度为: O ( 1 ) O(1) O(1)

为达到新的目标,可以直接在该代码上进行一些改变——用原始数组中扫描过的元素存储正整数的出现情况,具体实现如下:

int minAbsent(vector<int>& a){
	int n=a.size();
	// 扫描到a[i]时, 最大有正整数i+1已经出现
	// 故令: 将当前元素x的出现情况存储在扫描后的a[x-1]中
	for(int i=0; i<n; i++){
		int x=a[i];
		a[i]=0;
		if(x>=1 && x<=n){
			a[x-1] = 1;
		}
	}
	// 扫描a数组, 找到第一个未出现正整数
	for(int i=0; i<n; i++){
		if(!a[i]){
			return i+1;
		}
	}
	// [1,n]均出现, 返回n+1
	return n+1;
}

但对应地,这种优化也有相应的代价——原数组内的元素被修改了,具体在实际问题中是否采用此策略还需要慎重考虑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值