优质博文:IT-BLOG-CN
一、题目
给你一个整数数组nums
和一个整数k
,判断数组中是否存在两个不同的索引i
和j
,满足nums[i] == nums[j]
且abs(i - j) <= k
。如果存在,返回true
;否则,返回false
。
示例 1:
输入:nums = [1,2,3,1], k = 3
输出:true
示例 2:
输入:nums = [1,0,1,1], k = 1
输出:true
示例 3:
输入:nums = [1,2,3,1,2,3], k = 2
输出:false
1 <= nums.length <= 105
-109 <= nums[i] <= 109
0 <= k <= 105
二、代码
【1】滑动窗口: 数组nums
中的每个长度不超过k + 1
的滑动窗口,同一个滑动窗口中的任意两个下标差的绝对值不超过k
。如果存在一个滑动窗口,其中有重复元素,则存在两个不同的下标i
和j
满足nums[i] = nums[j]
且∣i−j∣ ≤ k
。如果所有滑动窗口中都没有重复元素,则不存在符合要求的下标。因此,只要遍历每个滑动窗口,判断滑动窗口中是否有重复元素即可。
如果一个滑动窗口的结束下标是i
,则该滑动窗口的开始下标是max(0,i−k)
。可以使用哈希集合存储滑动窗口中的元素。从左到右遍历数组nums
,当遍历到下标i
时,具体操作如下:
1、如果i > k
,则下标i − k − 1
处的元素被移出滑动窗口,因此将nums[i−k−1]
从哈希集合中删除;
2、判断nums[i]
是否在哈希集合中,如果在哈希集合中则在同一个滑动窗口中有重复元素,返回true
,如果不在哈希集合中则将其加入哈希集合。
当遍历结束时,如果所有滑动窗口中都没有重复元素,返回false
。
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
// 思想,采用滑动窗口的思想,定义两个指针,之间的最大距离为k,如果超过k,则进行下一次判断,慢指针向前一步;
if (nums != null && nums.length == 0) {
return false;
}
for (int i = 0; i < nums.length; i++) {
for (int j = i + 1; (j <= i + k && j < nums.length); j++) {
if (nums[i] == nums[j]) {
return true;
}
}
}
return false;
}
}
时间复杂度: O(n)
其中n
是数组nums
的长度。需要遍历数组一次,对于每个元素,哈希集合的操作时间都是O(1)
。
空间复杂度: O(k)
其中k
是判断重复元素时允许的下标差的绝对值的最大值。需要使用哈希集合存储滑动窗口中的元素,任意时刻滑动窗口中的元素个数最多为k+1
个。
【2】哈希表: 从左到右遍历数组nums
,当遍历到下标i
时,如果存在下标j<i
使得nums[i]=nums[j]
,则当i−j≤k
时即找到了两个符合要求的下标j
和i
。如果在下标i
之前存在多个元素都和nums[i]
相等,为了判断是否存在满足nums[i]=nums[j]
且i−j≤k
的下标j
,应该在这些元素中寻找下标最大的元素,将最大下标记为j
,判断i−j≤k
是否成立。
如果i−j≤k
,则找到了两个符合要求的下标j
和i
;如果i−j>k
,则在下标i
之前不存在任何元素满足与nums[i]
相等且下标差的绝对值不超过k
,当遍历到下标i
时,如果在下标i
之前存在与nums[i]
相等的元素,应该在这些元素中寻找最大的下标j
,判断i−j≤k
是否成立。
可以使用哈希表记录每个元素的最大下标。从左到右遍历数组nums
,当遍历到下标i
时,进行如下操作:
1、如果哈希表中已经存在和nums[i]
相等的元素且该元素在哈希表中记录的下标j
满足i−j≤k
,返回true
;
2、将nums[i]
和下标i
存入哈希表,此时i
是nums[i]
的最大下标。
上述两步操作的顺序不能改变,因为当遍历到下标i
时,只能在下标i
之前的元素中寻找与当前元素相等的元素及该元素的最大下标。当遍历结束时,如果没有遇到两个相等元素的下标差的绝对值不超过k
,返回false
。
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
// 思想:通过hashmap[key=nums中的元素,value = 下表],每次判断元素是否存在,存在则获取下表与当前的元素进行比较;
if (nums != null && nums.length == 0) {
return false;
}
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(nums[i]) && i - map.get(nums[i]) <= k) {
return true;
}
map.put(nums[i], i);
}
return false;
}
}
时间复杂度: O(n)
,其中n
是数组nums
的长度。需要遍历数组一次,对于每个元素,哈希表的操作时间都是O(1)
。
空间复杂度: O(n)
,其中n
是数组nums
的长度。需要使用哈希表记录每个元素的最大下标,哈希表中的元素个数不会超过n
。