1. 题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。
也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1
数据范围:0≤n≤10000
进阶:时间复杂度O(n),空间复杂度O(n)
2. 运行示例
输入:[2,3,1,0,2,5,3]
返回值:2
说明:2或3都是对的
3. 解决方法
3.1 方法一
思路:最容易想到的一种方法,对数组中的数据进行排序,然后一次遍历,比较找出第一个重复的数字进行返回。
代码实现:
int duplicate(vector<int>& numbers) {
// write code here
sort(numbers.begin(),numbers.end()); // 从小到大排序
for(int i = 1;i<numbers.size();++i) // 这里从1开始
if(numbers[i-1]==numbers[i]) // 判断当前数字是否和前面一个相同 即出现重复
return numbers[i];
return -1;
}
时间复杂度:O(nlogn)
3.2 方法二
思路:使用set集合,如果set集合中没有当前数字,那么将其加入到set集合中;
如果出现了当前数字,那么当前数字即出现重复,返回当前数字。
这里简单说明一下set集合的使用:set集合中将数据从大到小排列,且不含重复元素。
代码实现:
int duplicate(vector<int>& numbers) {
// write code here
set<int> s;
for(int i=0;i<numbers.size();++i){ // 遍历numbers
if(s.find(numbers[i]) == s.end()) // 如果find查询当前元素返回的是end迭代器 那么即集合中不含当前元素
s.insert(numbers[i]); // 将当前元素插入到set集合中
else
return numbers[i]; // 否则返回当前元素
}
return -1;
}
时间复杂度:O(n)
3.3 方法三
思路:注意题目中的一句话:“在一个长度为n的数组里的所有数字都在0到n-1的范围内。”,那么现在可以将元素和对应容器的下标对应起来,比如:
数组下标:0 1 2 3 4 5 6
对应元素:3 2 1 2 4 6 3
从头开始遍历数据,如果当前元素值和对应其下标值不相同,并且当前元素值和用当前元素作为下标的那个元素值不相同的话,那么将当前元素和与用当前元素做下标的元素进行交换,从而得到了一个数组下标和元素对应的数据;如果相同,那么继续查看下一元素,因此,上面举例可以进行如下变换:
数组下标:0 1 2 3 4 5 6
对应元素:2 2 1 3 4 6 3
数组下标:0 1 2 3 4 5 6
对应元素:1 2 2 3 4 6 3
数组下标:0 1 2 3 4 5 6
对应元素:2 1 2 3 4 6 3
此时如果再进行一次变换,可以发现[0]中元素2和[2]中元素2出现了重复,那么则返回该重复元素。
代码实现:
int duplicate(vector<int>& numbers) {
// write code here
for(int i = 0;i<numbers.size();++i){
while(numbers[i]!=i){
if(numbers[i] == numbers[numbers[i]])
return numbers[i];
else
swap(numbers[i],numbers[numbers[i]]);
}
}
return -1;
}
时间复杂度:O(n)
自己感觉第三中方法叙述解释的不是太好,欢迎批评指正。
——————END-2022-05-01——————