给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。
方法一:哈希法
哈希表记录每个数字是否出现,C++中可以使用 unorder_map,遍历数组记录每个数字是否出现
思路创建一个哈希表;标记nums每个数字出现的次数;如果出现的次数count=2,直接放到返回数组里面
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
vector<int> Duplicates(0);
int n =nums.size();
unordered_map<int,int> mp;
for(auto &num:nums){
mp[num]++;
}
for(auto &k:mp){
if(k.second == 2){
Duplicates.push_back(k.first);
}
}
return Duplicates;
}
};
方法二:原地哈希;空间复杂度O(1) 类似于 力扣 448题
不开辟额外空间,原数组 nums 是否可以作为哈希表来使用呢?
直接将数组 nums 作为哈希表,会覆盖原来的值,导致出错。
如何利用 nums 作为辅助数组,来记录每个数字是否出现呢?
对于第 i 个数字 nums[i],我们位置 (nums[i] - 1) % n 的位置增加 n,这样不会覆盖原数组,因为 (nums[i] - 1) % n = (nums[i] - 1 + n) % n
这样如果最后遍历完数组,nums[i] 大于 2*n时即说明这个数字是重复了两次的
由于1<=nums[i]<=n(数组长度),所以(nums[i]-1)可以成为nums中的下标
记index=(nums[i]-1)%n又因为1<=nums[i]<=n,
所以可以通过nums[i]每出现过一次之后对nums[index]+=n,确保当nums[index]>2*n时,index+1(即nums[i])出现过两次。
上图中 3 2是重复两次的他们对应的index分别为(3-1)%8=2 (2-1)%8=1;他们对应的新数组发生了变化
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
vector<int> Duplicates(0);
int n =nums.size();
int index =0;
for(int i =0;i<n;++i){
index = (nums[i]-1)%n; // 只有减去1才会出现index = 0的情况 index 在0~7内
nums[index]+=n; // 在新标签下叠加n重复两次一定会出现大于两倍n
if(nums[index]>2*n){
Duplicates.push_back(index+1); //重复的数字对应的index差值为1
}
}
return Duplicates;
}
};