题目
在一个长度为n的数组里的所有数字范围都在0~n-1之间,数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
例如
数组长度为8
数组为:{2,3,4,5,3,2,6,5}
重复数字为3或5
输入情况
1.数组范围在0~n-1,长度为n的数组里包含一个或多个重复数字
2.数组范围在0~n-1,数组中无重复数组
3.数组范围不在0~n-1
3.输入空数组
解决思路:
解决这个问题的办法很多,如:
1.先将数组排序,然后遍历数组,在遍历数组时就可以将元素与后一个元素比较。但是这样做的弊端是会改变我们传入的数组。
2.还可以开辟一个长度为n的数组并初始化为0,由于我们传入的数组范围在0~n之间,所以遍历我们传入的数组,然后在以元素做下标去访问我们新开数组值去做加1操作,然后判断数组中值是否大于2,若是的话,我们就找到了重复的数字。
3.由于题目中长度为n的数组的元素范围为0~n-1,若数组中没有重复数字则排序后数组元素就在其对应下标位置,反之,则不在其对应位置。
思路3续:
下面我继续思路3的完成这道题目,思路是:假设用i表示数组下标,数组名为arr,遍历数组,若数组元素与下标相等则下标加1;反之,持续完成下面操作直到不满足条件,先判断元素与以元素为下标所对应的元素是否相等,若相等则找到了重复元素,若不相等,则将这两个元素的位置进行交换。如下图:

按照上面的思路和前面给的例子,可以得到如下操作顺序【a,b,c,d,e],最后找到重复值2。

程序代码
//返回数组中任意一个重复元素,若数组长度为n,则数组元素范围为0到n-1
//条件:空间复杂度为O(1)
//时间复杂度为O(n)
#include<iostream>
using namespace std;
bool duplicate(int nums[], int len, int* duplication) {
//判空
if (nums == nullptr || len <= 0) {
return false;
}
//判断数组元素是否合法
for (int i = 0; i < len; i++) {
if (nums[i] < 0 || nums[i] >= len) {
return false;
}
}
//遍历数组
for (int i = 0; i < len; i++) {
//循环交换
while (nums[i] != i) {
//找到重复值时
if (nums[i] == nums[nums[i]]) {
*duplication = nums[i];
return true;
}
//nums[i]与第nums[i]个数交换,i不++,再比较一次
/*int temp = nums[i];
nums[i] = nums[nums[i]];
nums[nums[i]] = temp;*///不能写成这样,因为nums[i]的值已经改变了
int temp = nums[i];
nums[i] = nums[temp];
nums[temp] = temp;
}
}
//执行完了,就是没找到
return false;
}
小结:
从上面结果分析知,总时间复杂度为O(n),虽然这种方法不需要额外分配空间,即空间复杂度为O(1),但是数组的结构被改变了

3839

被折叠的 条评论
为什么被折叠?



