题目:
给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。
例 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
解法一:暴力求解
这是我首先想到的。遍历数组,对于每一个元素,判断它前后k个索引范围内是否有和它值相同的元素,如果有,直接返回true;没有,就什么都不做,继续遍历下一个元素。
这个范围可以缩小一半,只判断从i~i+k的范围,因为左边一半如果有值相等的,那肯定在之前遍历前边元素的时候就被找出来了,既然能遍历到当前这个元素,就说明当前元素前边k个里,没有满足要求的。所以不需要重复判断了。
var containsNearbyDuplicate = function(nums, k) {
let j
for(let i=0;i<nums.length;i++){
j= i
while(j<=Math.min(i+k,nums.length-1)){
if(i!==j && nums[j]===nums[i]){
return true
}
j++
}
}
return false
};
j就是滑动窗口的每一项,它的范围是i~i+k,但是不能超出数组索引。
解法二:利用set控制范围
题目的关键点是找出一个重复的元素,而且该元素与当前元素的位置必须在一定范围内。说到重复,set数据结构里是不会有重复项的。我们可以在遍历数组的同时,维护一个set,遍历每一个元素,如果在set里没有相同元素,就把该元素放进去。如果set里已经有了相同元素,怎么判断它与当前元素是否在k个范围内呢?那怎么控制范围呢?可以控制set的大小始终不超过k个。比如k=2,那就让set的长度<=2。把当前元素放进去之后,每次都要判断长度,如果超过了2个,就把当前i -k位置处的元素删掉,保持set里最多只有2个元素。
这样做,因为set里始终最多有2个元素,所以如果遍历到当前元素i,发现set里有相同的值,那就说明它俩一定在k的范围内,那就直接返回true
var containsNearbyDuplicate = function(nums, k) {
let set=new Set()
for(let i=0;i<nums.length;i++){
if(set.has(nums[i])){
return true
}
set.add(nums[i])
if(set.size>k){
set.delete(nums[i-k])
}
}
return false
};
和方法一相比,时间缩短了很多。