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

相关推荐
HPtiger5 小时前
数据结构——选择排序
数据结构·算法·排序算法
康实训5 小时前
老年评估仿真实训平台架构设计与老年人能力评估实训室教学落地实践
大数据·人工智能·算法·实训室·实训室建设
DongQiShanRen6 小时前
六根硬件映射(四):归属澄清、两处不一致与卷十一总表
开发语言·人工智能·算法·rust·哈希算法·集成学习
CCblandy6 小时前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构
丑梨数据6 小时前
信创环境里跑文档工具:格式兼容与本地合规的几个坑
数据结构·人工智能·算法·决策树·排序算法
erzong2318 小时前
Linux操作系统:线程概念与控制
linux·算法
Nil2088 小时前
leetcode 5最长回文子串
算法·leetcode·职场和发展
xxwl5858 小时前
区域赛分类题解
c++·笔记·学习·算法
m0_674571979 小时前
力扣 hot 100 python
python·算法·leetcode
开开心心就好9 小时前
多份文档怎么批量打印?支持多种格式
java·服务器·开发语言·pdf·ocr·散列表·启发式算法