爱奇艺笔试题:
原题是:已知一个数组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;
}
第二种方法不管简易性还是出错率还是易读性完爆我自己的第一种方法有木有!!!