题目要求
思路
思路一:
双重循环,第一重循环遍历nums内的元素,从第一个元素遍历到最后一个元素。第二重循环遍历i+1元素到i+k元素,如果存在元素与i元素的值相同,就返回true,如果遍历完整个集合都没有,就返回false。时间复杂度为O(N²)。
代码:
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
for(int i=0;i<nums.size();i++){
for(int j=i+1;j<=i+k;j++){
if(j>=nums.size()) break;
if(nums[j]==nums[i])
return true;
}
}
return false;
}
};
运行结果:
总结反思:
因为是使用了双重循环,所以时间复杂度为O(N^2)。时间消耗大,所以考虑降低算法的时间复杂度。
思路二:
使用C++ STL中的set来降低第二重循环的时间消耗,第一重循环不变,第二重循环改为使用set的count()函数来查找set集合中是否存在相同的元素,并且维持set的集合的size为k,对应nums数组中一段连续的范围。当set集合的范围到达k时,便删除set集合中对应数组范围的第一个元素。相当于在k的范围内找set中第一个元素相同的值。思路与思路一基本一致。时间复杂度O(N)。
代码:
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
set<int> s;
set<int>::iterator it;
for(int i=0;i<nums.size();i++){
if(s.count(nums[i])==1) return true;
s.insert(nums[i]);
if(s.size()>=k+1) {
it = s.find(nums[i-k]);
s.erase(it);
}
}
return false;
}
};
运行结果:
总结与反思:
相比较unordered_map而言,set的count()与find()函数消耗时间更大一点,所以考虑改成unordered_map。
思路三:
将set改为unordered_map,因为unordered_map可以保存两个值,所以不再需要维持k的范围,当查找到相同元素时,判断坐标之差是否小于k即可。时间复杂度O(N)。
代码:
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
if(k<=0) return false;
if(nums.size()==0 || nums.size()==1) return false;
unordered_map<int,int> num;
for(int i=0;i<nums.size();i++){
if(num.find(nums[i]) == num.end())
num.insert({nums[i],i});
else{
if(i-num[nums[i]]<=k)
return true;
else
num[nums[i]] = i;
}
}
return false;
}
};
运行结果:
总结与反思:
在考虑哈希结构时,能用unordered_map就尽量用unordered_map。会大幅度降低时间消耗。