【剑指Offer-数组】面试题3:数组中的重复数字
题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
思路1
先排序,然后遍历数组,如果 nums[i]==nums[i+1],则说明 nums[i] 重复,返回 nums[i] 即可。代码如下:
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
sort(nums.begin(), nums.end());
for(int i=0; i<nums.size()-1; i++){
if(nums[i]==nums[i+1]) return nums[i];
}
return 0;
}
};
- 时间复杂度:O(nlogn)
- 空间复杂度:O(1)
思路2
使用哈希表。从头到尾扫描数组,每扫描到一个数字时,就用O(1)的时间来判断哈希表中是否包含了该数字。如果包含,就找到了一个重复数字;如果没有包含,就把该数字加入到哈希表中。
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
vector<bool> hash(nums.size(), false);
for(int i=0; i<nums.size(); i++){
if(hash[nums[i]]==true) return nums[i];
else hash[nums[i]] = true;
}
return 0;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(n)
思路3
使用和缺失的第一个正数类似的方法。遍历 nums,并将 nums[nums[i]] 设为 -nums[nums[i]],这样,在遍历的过程中,如果我们先 nums[nums[i]] 为负数,则说明 nums[i] 是重复的。
这个方法还有一个问题要解决,就是 0 的问题。我们设置一个标志 findZero 表示是否找到了 0,如果第一次找到 0,则将 findZero 设为 true,如果我们在找到 0,则将 0 的下标返回即可。代码如下:
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
bool findZero = false;
for(int i=0; i<nums.size(); i++){
int idx = abs(nums[i]);
if(nums[idx]==0){
if(findZero==true) return idx;
else findZero = true;
}else if(nums[idx]<0){
return idx;
}else{
nums[idx] = -nums[idx];
}
}
return 0;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(1)
思路4
遍历数组,如果 nums[i]==i,说明 i 没有缺失,判断下一个元素。如果 nums[i]!=i,则交换 nums[i] 和 nums[nums[i]],如果在交换的过程中发现 nums[i]==nums[nums[i]],则返回 nums[i]。代码如下:
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
for(int i=0; i<nums.size(); i++){
if(nums[i]!=i){
while(nums[i]!=i){
if(nums[i]==nums[nums[i]]) return nums[i];
else swap(nums[i], nums[nums[i]]);
}
}
}
return 0;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(1)