LeetCode笔记:存在重复元素 II

问题

给定一个整数数组和一个整数  k,判断数组中是否存在两个不同的索引 i  和 j,使得  nums [i] = nums [j],并且 ij  的差的 绝对值 至多为 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

解法一

思路:

用一个对象来存储每个数字的信息,利用 key 不能重复的原理,每次遇到新的重复的数字,就更新位置信息和最近一个重复数字的绝对值,一旦遇到一个绝对值比k小就是成功找到了想要的数字。

代码:

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {boolean}
 */
var containsNearbyDuplicate = function (nums, k) {
  // 初始化存储空间
  const obj = {};

  // 一遍循环即可,遍历所有的数字
  for (let i = 0; i < nums.length; i++) {
    // 当前数字
    const n = nums[i];

    // 是否出现重复数字
    if (n in obj) {
      // 重复出现的数字,绝对值需要更新为和前一个值的差,因为和前一个的差肯定更小
      obj[n].abs = i - obj[n].i;
      // 上面计算完差值,就可以更新当前位置了,用于下一次重复出现的时候计算差值
      obj[n].i = i;

      // 一旦发现当前差值小于k,即满足条件退出
      if (obj[n].abs <= k) return true;
    } else {
      // 第一次出现的数字进行初始化,存储位置和绝对值(因为第一次出现,所以绝对值为0)
      obj[n] = {
        i: i,
        abs: 0,
      };
    }
  }

  //如果上面的循环中没有找到满足条件的数字,默认返回`false`
  return false;
};

解法二

思路:

利用Set不允许重复元素的特性,做一个k大小的滑动窗口,一直往前滑动寻找窗口内是否出现相同元素。这个滑动窗口需要的空间更小。

代码:

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {boolean}
 */
var containsNearbyDuplicate = function (nums, k) {
  const set = new Set();
  for (let i = 0; i < nums.length; i++) {
    // 滑动窗口内一旦出现重复元素,即满足要求
    if (set.has(nums[i])) {
      return true;
    }
    // 每个值都加入
    set.add(nums[i]);

    // 一旦数量超出k,就删除第一个数字,即滑动窗口右移
    if (set.size > k) {
      set.delete(nums[i - k]);
    }
  }
  return false;
};

参考

评论