LeetCode 219简单哈希表
存在重复元素 II 图解题解
这道题到底在问什么
给你一个整数数组 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
先想最直接的笨办法
暴力法重复比较了太多下标对。我们真正需要的是:当前 x 上一次在哪里出现过?(动画第 3 步)
最优解:一步一步想明白
- 3暴力法重复比较了太多下标对。我们真正需要的是:当前 x 上一次在哪里出现过?
- 4为什么记录最近下标就够?如果最近一次都离当前超过 k,更早的出现位置只会更远,更不可能满足条件。
- 5last = {}last 的含义是“值 -> 最近一次出现的下标”。刚开始还没看任何数,所以为空。
- 6if x in last ... # False当前 1 之前没出现过,无法判断距离,先准备记录它的位置。
- 7last[x] = i把 1 的最近下标记为 0。以后再遇到 1,就和下标 0 比距离。
- 8if x in last ... # False; last[x] = i0 也是第一次出现,直接记录最近下标 1。
- 9i - last[x] <= k ? 2 - 0 <= 1这里虽然又遇到 1,但两个下标 0 和 2 的距离是 2,超过 k=1,不能返回 true。
- 10last[x] = i这一步很关键:要保存最近下标。下次再遇到 1,应该和更近的下标 2 比,而不是继续和 0 比。
- 11if x in last and i - last[x] <= k: return True这次 1 和上一次 1 的距离只有 1,满足题意,直接返回 true。
- 12return True一旦找到满足条件的一对下标,就不用继续扫描。这个提前返回也是哈希题常见的写法。
- 15这题的迁移点是:哈希表的 value 不一定是次数,也可以是最近位置、状态或对象。
⚠️ 容易写错的地方
✗ 错:只判断 x 是否出现过
✓ 对:还要判断 i - last[x] <= k
题目要求的是“附近”的重复元素。
✗ 错:保存第一次出现的位置
✓ 对:每次都更新为最近出现的位置
最近位置更可能满足距离限制,更早的位置只会更远。
✗ 错:比较 nums[i] 和 nums[j] 的值差
✓ 对:比较下标差 abs(i-j)
k 限制的是索引距离,不是数值大小。
完整代码(Python)
Python
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复杂度
时间复杂度
O(n)
每个元素只扫描一次,哈希查找平均 O(1)。
空间复杂度
O(n)
last 最多保存数组中不同值的最近下标。
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 存在重复元素 II 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这道题为什么用「哈希表」,换最直接的暴力解会差在哪?+
哈希表抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
时间复杂度为什么是 undefined?怎么推出来的?+
按上文复杂度小节的推导,时间复杂度为 undefined。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。