在O(n)时间复杂度O(1)空间复杂度求一个数组中出现多次和未出现的数字

本文提供了一道爱奇艺笔试题的两种解法,要求时间复杂度为O(N),空间复杂度为O(1)。通过巧妙利用数组特性,第一种方法通过交换元素定位重复与缺失值;第二种方法使用取模运算更新数组实现相同目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

爱奇艺笔试题:

原题是:已知一个数组A[],大小为N,其中每个数都为1~N,请求出该数组中未出现的数字和出现多次的数字。

要求是时间复杂度为O(N),空间复杂度为O(1)


这道题的关键点就在于空间复杂度为O(1),本来想到的2-bitmap因为这点也不能实现了。


解法一:

这是我自己考试时想到的,利用每个数都为1~N的特点,可以将A[I]与A[A[I] - 1]进行交换,一直到无法交换为之。交换过后,如果为重复则将该数置为-1,如果未出现则置为0.

这种方法边界条件较为复杂,很难在考场上写的尽善尽美。

分析复杂度,交换次数将不会超过N,而比较次数稍多,但也不会超过2N。因此总体可以认为时间复杂度依然在O(N)的范围。

代码如下:

void appears1(int r[], int n) {
	int i;
	for (i = 0; i < n; ++i) {
		if (r[i] == i + 1 || r[i] == -1 || r[i] == 0)
			continue;
		else if (r[i] == r[r[i] - 1]) {
			r[r[i] - 1] = -1;
			r[i] = 0;
		} else if (r[r[i] - 1] == -1)
			r[i] = 0;
		else {
			int j = i;
			while (r[j] != 0 && r[j] != r[r[j] - 1] && r[r[j] - 1] != -1)
				swap(r[j], r[r[j] - 1]);
			if (r[j] != j + 1) {
				r[r[j] - 1] = -1;
				r[j] = 0;
			}
		}
	}
	cout << "未出现的数字为: ";
	for (i = 0; i < n; ++i)
		if (r[i] == 0)
			cout << i + 1 << " ";
	cout << endl;
	cout << "出现多次数字为: ";
	for (i = 0; i < n; ++i)
		if (r[i] == -1)
			cout << i + 1 << " ";
	cout << endl;
}


解法二:

强烈值得注意!

啥都不说了,直接看代码吧。提示是:要善于利用%操作符
void appears(int r[], int n) {
	int i;
	for (i = 0; i < n; ++i)
		r[(r[i] - 1) % n] += n;
	cout << "未出现的数字为: ";
	for (i = 0; i < n; ++i)
		if ((r[i] - 1) / n == 0)
			cout << i + 1 << " ";
	cout << endl;
	cout << "出现多次数字为: ";
	for (i = 0; i < n; ++i)
		if ((r[i] - 1) / n > 1)
			cout << i + 1 << " ";
	cout << endl;
}


第二种方法不管简易性还是出错率还是易读性完爆我自己的第一种方法有木有!!!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值