LeetCode 219 存在重复元素 II

1. 题目

219. 存在重复元素 II

题目描述

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

  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,但规范建议保留)。

相关推荐
用户979984807185 小时前
200 行代码写一个能跑的 AI Agent:不依赖任何框架,只靠 tool-calling 原理
算法
threerocks5 小时前
【Muse实战】X 流量作战室搭建保姆级教程 - 拥有你自己的运营团队
算法
GreenTea5 小时前
深度拆解 ScienceBuddy:如何用“双层递归自进化”构建高可靠科研 Agent Harness
前端·后端·算法
花椒技术5 小时前
2.46 秒生成 5 秒视频:拆解 H3 Max 的模型、推理栈与硬件协同
算法·音视频开发·视频编码
vivo互联网技术6 小时前
ART:妆容迁移框架,重新定义高保真妆容迁移 | ECCV 2026
人工智能·算法·图像识别
用户0441440924496 小时前
卫星信号模拟器里的四个坐标转换公式
算法
橘和柠6 小时前
阿里 open-code-review (AI代码审查工具)实战:安装、四层规则链、自定义规则格式与实测避坑
算法·面试
得物技术6 小时前
别再只卷向量检索了,得物交易搜索如何用“生成式”实现召回范式跃迁?
人工智能·算法·llm
罗西的思考6 小时前
[Agent Memory / 强化学习] MemPO源码学习笔记 ---(4)--- Rollout实现细节
人工智能·算法
罗西的思考6 小时前
机器人 / 物理 Agent Harness 综合分析与对比:从「更强的模型」到「更好的系统」
人工智能·算法·机器学习