问题描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1
数据范围
0 <= n <= 10000
示例
输入:[2,3,1,0,2,5,3]
返回值:2
说明:2或3都是对的
思路
首先数组里面的所有数字都在0到n - 1的范围内,所以需要遍历完整个数组寻找是否有不合法的数字。
题目要求只要找到任意一个重复的数字即可,所以只要找到一个重复的数字即可返回输出。
故时间复杂度最少也是O(n)。
思路一 暴力破解
暴力破解:第一层选择数组中的一个数字,与剩下的n-1个数字进行比较,若发现相同的两个数字,就返回正确的结果。
复杂度:
时间复杂度:O(n^2)
空间复杂度:O(1)
代码如下:
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int n = nums.size();
for (auto num : nums)
if(num < 0 || num > n) return -1;
//核心代码
for (int i = 0; i < n - 1; i ++ )
for (int j = i + 1; j < n; j ++ )
if(nums[i] == nums[j]) return nums[i];
return -1;
}
};
思路二 排序后遍历
排序后遍历:
- 首先对数组进行排序推荐使用sort()可达到O(nlogn)的复杂度
- 之后遍历数组即可,若发现有两个连续的元素即返回。
复杂度:
时间复杂度:O(nlogn)
空间复杂度:O(1)
代码如下:
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int n = nums.size();
for (auto num : nums)
if(num < 0 || num > n) return -1;
//核心代码
sort(nums.begin(), nums.end());
for (int i = 0; i < n - 1; i ++ )
if (nums[i] == nums[i + 1]) return nums[i];
return -1;
}
};
思路三 hash散列
Hash散列:
- 遍历一遍nums数组,并且查询hash表
- 如果说查询表中已有那么就返回该数,如果没有那么添加进去即可。
复杂度分析:
时间复杂度:O(n),只遍历了一遍
空间复杂度:O(n),最坏情况将数组中的所有数存入hash表中
代码如下:
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int n = nums.size();
for (auto num : nums)
if(num < 0 || num > n) return -1;
//核心代码
set<int> res;
for (int i = 0; i < n; i ++ )
if(res.count(nums[i]) > 0) return nums[i];
else res.insert(nums[i]);
return -1;
}
};
虽然使用hash表的时间的复杂度可以达到O(n),但是空间复杂度也达到了O(n),所以需要一种新的方法来找重复的数字。
思路四 数据重排
数据重排:
- 扫描数组nums中的每一个元素,当扫描到第i个元素的时候,比较i与nums[i]是否相等,如果相等说明i已经归位了
- 如果不相等,那么比较nums[i]与nums[nums[i]]是否相等,如果不相等那么交换两个元素的位置,让num[i]归位.
- 如果相等那么就意味着有重复的元素,即返回。
复杂度分析:
时间复杂度:O(2n),扫描一遍,交换一遍
空间复杂度:O(1)
图解:
代码如下:
class Solution {
public:
int duplicateInArray(vector<int>& nums) {
int n = nums.size();
for (auto num : nums)
if(num < 0 || num > n) return -1;
//核心代码
for (int i = 0; i < n; i ++ ) {
if (i != nums[i] && nums[i] != nums[nums[i]])
swap(nums[i], nums[nums[i]]);
if (i != nums[i] && nums[i] == nums[nums[i]])
return nums[i];
}
return -1;
}
};
参考:《剑指Offer》