§1
题目描述
给你一个整数数组 nums 和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,满足 nums[i] == nums[j] 且 abs(i - j) <= k。如果存在返回 true,否则返回 false。
输入 = 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
§2
思路解析动画文字版
暴力法重复比较了太多下标对。我们真正需要的是:当前 x 上一次在哪里出现过?
为什么记录最近下标就够?如果最近一次都离当前超过 k,更早的出现位置只会更远,更不可能满足条件。
初始化 last 为空:last 的含义是“值 -> 最近一次出现的下标”。刚开始还没看任何数,所以为空。
i=0,x=1:第一次见:当前 1 之前没出现过,无法判断距离,先准备记录它的位置。
记录 1 的最近下标:把 1 的最近下标记为 0。以后再遇到 1,就和下标 0 比距离。
i=1,x=0:第一次见:0 也是第一次出现,直接记录最近下标 1。
i=2,x=1:重复了,但距离太远:这里虽然又遇到 1,但两个下标 0 和 2 的距离是 2,超过 k=1,不能返回 true。
更新 1 的最近下标为 2:这一步很关键:要保存最近下标。下次再遇到 1,应该和更近的下标 2 比,而不是继续和 0 比。
i=3,x=1:距离 1,满足条件:这次 1 和上一次 1 的距离只有 1,满足题意,直接返回 true。
命中条件:函数提前结束:一旦找到满足条件的一对下标,就不用继续扫描。这个提前返回也是哈希题常见的写法。
这题的迁移点是:哈希表的 value 不一定是次数,也可以是最近位置、状态或对象。
§3
参考代码
class Solution: def containsNearbyDuplicate(self, nums, k): last = {} for i, x in enumerate(nums): if x in last and i - last[x] <= k: return True last[x] = i return False看懂代码不等于写得出。盖住上面,自己默写一遍试试。卡在哪一行说不清,就点右下角问小欧。
§4
复杂度
- 时间复杂度:O(n),每个元素只扫描一次,哈希查找平均 O(1)。
- 空间复杂度:O(n),last 最多保存数组中不同值的最近下标。
§5
易错点
✗ 错误写法:只判断 x 是否出现过
✓ 正确写法:还要判断 i - last[x] <= k
题目要求的是“附近”的重复元素。
✗ 错误写法:保存第一次出现的位置
✓ 正确写法:每次都更新为最近出现的位置
最近位置更可能满足距离限制,更早的位置只会更远。
✗ 错误写法:比较 nums[i] 和 nums[j] 的值差
✓ 正确写法:比较下标差 abs(i-j)
k 限制的是索引距离,不是数值大小。
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
下一题 · 哈希套路 4/8
→两个数组的交集
LeetCode 349 · 简单 · 沿着 哈希套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
299道动画图解
37节语音讲解
28课数据结构
¥0.27折合 / 天
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
¥99 开通年卡 →
想成体系刷透这类套路?去图解算法专题