LeetCode 219 存在重复元素 II

1. 题目

219. 存在重复元素 II

题目描述

给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个不同的下标 ij,满足:

  1. nums[i] == nums[j]

  2. (abs(i-j) <= k)

示例

输入:nums = 1,2,3,1, k = 3

输出:true

输入:nums = 1,0,1,1, k = 1

输出:true

输入:nums = 1,2,3,1,2,3, k = 2

输出:false

约束

  • (1 <= nums.length <= 10^5)

  • (-10^9 <= numsi <= 10^9)

  • (0 <= k <= 10^5)

2. 最佳解题思路描述(哈希表存储上一次出现下标,一次遍历)

  1. 哈希表 unordered_map<int, int>:key = 数组数值,value = 该数值上一次出现的下标;

  2. 逐个遍历数组,当前下标i、数值x=numsi

    • 如果哈希表存在x:计算当前下标与上次下标差值,若 ≤k 直接返回 true;

    • 无论是否匹配成功,都更新哈希表中x对应的下标为当前i(只保留最近一次下标,后续更易满足间距条件);

    • 不存在则插入当前数值与下标;

  3. 遍历结束无满足条件则返回 false。

优势

时间 (O(n)),仅一次遍历;空间 (O(n)) 最坏;逻辑直观,适合大数据量。

3. 可优化代码(逻辑正确,分支冗余,结构繁琐)

复制代码
class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) {
        unordered_map<int,int> hash;
        for(int i = 0;i<nums.size();i++){
            auto it = hash.find(nums[i]);
            if(it != hash.end()){
                if(abs(i-it->second)<=k){
                    return true;
                }
                it->second = i;
            }
            if(it == hash.end()){
                hash.insert({nums[i],i});
            }
        }
        return false;
    }
};

代码说明

  1. 正确性:无逻辑 bug,全部用例可通过;

  2. 冗余 / 可优化点:

    • 两次hash.find查找,重复查询哈希,浪费性能;

    • if(it != hash.end())if(it == hash.end()) 互斥,可用 else 简化;

    • 命名hash改为lastIdx语义更清晰;

    • 插入更新可统一简写 hash[nums[i]] = i,无需区分 insert;

    • 提前缓存nums[i]减少重复取值。

4. 规范简化版代码(哈希表最优写法)

复制代码
#include <unordered_map>
#include <vector>
#include <cmath>
using namespace std;
class Solution {
public:
    bool containsNearbyDuplicate(vector<int>& nums, int k) {
        unordered_map<int, int> lastIdx;
        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            int x = nums[i];
            auto it = lastIdx.find(x);
            if (it != lastIdx.end()) {
                if (abs(i - it->second) <= k) {
                    return true;
                }
            }
            // 无论存在与否,都更新为当前下标
            lastIdx[x] = i;
        }
        return false;
    }
};

5. 总结

  1. 核心规则:相同数字只保留最近一次下标,差值最小,更容易满足间距≤k;

  2. 关键优化:不用分开 insert / 更新,直接赋值 map[key]=val 自动覆盖旧值;

  3. 代码分支判断重复查询哈希,可读性与效率较差,用 else 合并分支更简洁;

  4. 找到满足条件的一对下标可直接 return,无需遍历完整数组。

6. 相关知识拓展

拓展 1:滑动窗口集合解法(空间更省,窗口大小 k)

维护窗口内最多 k 个元素,集合只保存滑动窗口内数字,空间 (O(k)):

复制代码
#include <unordered_set>
bool containsNearbyDuplicate(vector<int>& nums, int k) {
    unordered_set<int> win;
    int n = nums.size();
    for (int i = 0; i < n; ++i) {
        if (win.count(nums[i])) return true;
        win.insert(nums[i]);
        // 窗口超过k,移除窗口最左侧元素
        if (win.size() > k) {
            win.erase(nums[i - k]);
        }
    }
    return false;
}

拓展 2:复杂度对比

  1. 哈希存储上一次下标(优化版):(O(n)) 时间,(O(n)) 空间;

  2. 滑动窗口集合:(O(n)) 时间,(O(k)) 空间,k 较小时更省内存。

拓展 3:易错点复盘

  1. 匹配成功后忘记更新当前下标,后续判断会和旧下标对比,出现错误;

  2. 重复执行find多次查询哈希,性能冗余;

  3. 下标差值忘记取绝对值(i 一定大于上次下标,本题可省略 abs,但规范建议保留)。

相关推荐
知无不研2 小时前
c语言中循环的介绍与简单应用
c语言·开发语言·算法·循环·for·while
a187927218313 小时前
【算法】动态规划第四篇:背包收官——min 哨兵、计数世界与组合排列分水岭
算法·leetcode·动态规划·dp·01背包·算法讲解·决策合并
2601_962297483 小时前
在python3中、下列输出变量a的正确写法是_2020超星大数据Python免费答案
数据结构·python·算法·编程·字符串操作
辰烨chenye4 小时前
LeetCode Hot 100 题解 · 子串篇
算法·leetcode·职场和发展
辰烨chenye4 小时前
LeetCode Hot 100 题解 · 堆篇
java·算法·leetcode
手写码匠4 小时前
华为云Flexus+DeepSeek征文|DeepSeek 应用监控告警体系实战:从“用户投诉才知道“到“故障前就发现“
人工智能·深度学习·算法·aigc
shehuiyuelaiyuehao5 小时前
算法29,前缀和,除自身以外的数组的乘积
java·数据结构·算法
智购科技自动售货机厂家5 小时前
2026自动售货机设备清洁效果自动验证:从图像比对到评分算法的工程实践~YH
人工智能·算法·计算机视觉
姜穆澜5 小时前
机器学习实战指南:从算法原理到工程落地
人工智能·算法·机器学习