作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处
题目描述:
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1
数据范围:0≤n≤10000
进阶:时间复杂度O(n) ,空间复杂度O(n)
示例:
输入:
[2,3,1,0,2,5,3]
返回值:
2
说明:
2或3都是对的
解题思路:
本题是排序类题目,四种解题思路:
1)暴力法
双循环遍历,找到重复数字返回。时间复杂度O(n^2),空间复杂度O(1)。
2)排序遍历法
用快速排序将数组排序,再遍历搜索。时间复杂度O(nlogn),空间复杂度O(1)。
3)哈希表
用哈希表判断数字是否重复,可以用哈希set或者哈希map。哈希表查询O(1),所以只需遍历一轮即可完成。时间复杂度O(n),空间复杂度O(n)。
4)下标哈希法
将数组下标作为哈希键,比如数字2就把它放在数组下标2的位置,原先下标2位置的数字移动到数字2本来的位置,完成交换;依次类推,直到某次交换发现数字x和下标x的数字冲突了,说明找到重复值了;最坏的情况就是没有重复数字,把所有下标都遍历交换过一轮。时间复杂度O(n),空间复杂度O(1)。
注意:应用该方法的前提是如题目给定的条件那般,数字大小范围在0到n-1之间,不然就越界了。
测试代码:
1)暴力法
class Solution {
public:
// 寻找重复数据
int duplicate(vector<int>& numbers) {
int size= int(numbers.size());
for (int i = 0; i < size; ++i){
for (int j = i + 1; j < size; ++j){
if (numbers[i] == numbers[j])
return numbers[i];
}
}
return -1;
}
};
2)排序遍历法
class Solution {
public:
// 寻找重复数据
int duplicate(vector<int>& numbers) {
// 快排
sort(numbers.begin(),numbers.end());
int size = int(numbers.size());
// 寻找重复值
for(int i = 1; i <size; ++i){
if(numbers[i] == numbers[i - 1])
return numbers[i];
}
return -1;
}
};
3)哈希表
class Solution {
public:
// 寻找重复数据
int duplicate(vector<int>& numbers) {
// 哈希set
unordered_set<int> us;
int size = int(numbers.size());
for(int i = 0; i < size; ++i){
if(us.count(numbers[i]))
return numbers[i];
else
us.insert(numbers[i]);
}
return -1;
}
};
4)下标哈希法
class Solution {
public:
// 寻找重复数据
int duplicate(vector<int>& numbers) {
// 下标哈希法
int size = int(numbers.size());
for(int i = 0; i < size;){
if(numbers[i]==i)
i++;
else{
if(numbers[numbers[i]] == numbers[i])
return numbers[i];
else{
swap(numbers[numbers[i]], numbers[i]);
}
}
}
return -1;
}
};