题目来源
题目描述
题目解析
哈希表
从左到右遍历数组nums,当遍历到下标 i i i时,如果存在下标 j < i j < i j<i使得 n u m s [ i ] = = n u m s [ j ] nums[i] == nums[j] nums[i]==nums[j],则当 i − j < = k i - j <= k i−j<=k时即找到了两个符号要求的下标j和i。
如果在下标 i i i之前存在多个元素都和 n u m s [ i ] nums[i] nums[i]相等,为了判断是否存在满足 n u m s [ i ] = = n u m s [ j ] nums[i] == nums[j] nums[i]==nums[j]而且 i − j < = k i - j <= k i−j<=k的下标 j j j,应该在这些元素中寻找下标最大的元素,将最大下标记为 j j j,判断 i − j < = k i - j <= k i−j<=k是否成立。
- 如果 i − j < = k i - j <= k i−j<=k,则找到了两个符合要求的下标 j 和 i;
- 如果 i − j > k i - j > k i−j>k,则在下标 i i i之前不存在任何元素满足与nums[i]相等而且下标差的绝对值不超过 k k k
因此,当遍历到下标i时,如果在下标i之前存在于 n u m s [ i ] nums[i] nums[i]相等的元素,应该在这些元素中寻找最大的下标j,判断 i − j < = k i - j <= k i−j<=k是否成立。
可以使用哈希表记录每个元素的最大下标。从左到右遍历数组nums,当遍历到下标i时,进行如下操作:
- 如果哈希表中已经存在和 n u m s [ i ] nums[i] nums[i]相等的元素而且该元素在哈希表中记录的下标 j j j满足 i − j < = k i - j <= k i−j<=k,返回true
- 将 n u m s [ i ] nums[i] nums[i]和下标 i i i存入哈希表,此时i是 n u m s [ i ] nums[i] nums[i]的最大下标
上面两步操作的顺序不能改变,因为当遍历到下标 i i i时,只能在下标 i i i之前的元素中寻找与当前元素相等的元素以及该元素的最大下标
当遍历结束时,如果没有遇到两个相等元素的下标差的绝对值不超过k,返回false
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
std::unordered_map<int, int> map;
for (int i = 0; i < nums.size(); ++i) {
auto it = map.find(nums[i]);
if(it != map.end() && i - it->second <= k ){
return true;
}else{
map[nums[i]] = i;
}
}
return false;
}
};
复杂度分析:
滑动窗口
考虑数组nums中的每个长度不超过 k + 1 k + 1 k+1的滑动窗口,同一个滑动窗口中的任意两个下标差的绝对值不超过k。
- 如果存在一个滑动窗口,其中有重复元素,则存在两个不同的下标 i i i和 j j j满足 n u m s [ i ] = n u m s [ j ] nums[i] = nums[j] nums[i]=nums[j]而且 ∣ i − j ∣ < = k |i - j| <= k ∣i−j∣<=k。
- 如果所有滑动窗口中都没有重复元素,则不存在符合要求的下标。
因此,只要遍历每个滑动窗口,判断滑动窗口中是否有重复元素即可。
如果一个滑动窗口的结束下标是 i i i,则该滑动窗口的开始下标是 m a x ( 0 , i − k ) max(0, i-k) max(0,i−k)。可以使用哈希集合存储滑动窗口中的元素。从左到有遍历数组 n u m s nums nums,当遍历到下标 i i i时,具体操作如下:
- 如果 i > k i > k i>k,则下标 i − k − 1 i - k - 1 i−k−1处的元素被移除滑动窗口,因此将nums[i - k - 1]从哈希集合中删除、
- 判断nums[i]是否在哈希集合中,如果在哈希集合中则在同一个滑动窗口中有重复元素,返回 true,如果不在哈希集合中则将其加入哈希集合
当遍历结束时,如果所有滑动窗口中都没有重复元素,返回false
bool containsNearbyDuplicate(vector<int>& nums, int k) {
std::unordered_set<int> s;
for (int i = 0; i < nums.size(); ++i) {
if(i > k){
s.erase(nums[i - k - 1]);
}
if(s.count(nums[i])){
return true;
}
s.emplace(nums[i]);
}
return false;
}
复杂度分析: