《leetcode219. 存在重复元素 II》

268 阅读1分钟

题目:

给定一个整数数组和一个整数 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
};

和方法一相比,时间缩短了很多。