存在重复元素 II 图解题解
这道题到底在问什么
- 输入
- nums = [1,2,3,1],k = 3
- 输出
- true(下标 0 和 3 都是 1,距离 3 ≤ k)
最优解:一步一步想明白
- 3口诀:一张表 last 记每个数字「最后一次出现的下标」。每到一个数,先查上次位置算距离,再用这次下标覆盖。先查后更新。下面逐格演示。
- 4指针 i 走到下标 0,值是 1。去表里查 1 之前在哪:表里还没有它。
- 51 是第一次出现,把它的下标 0 记进表里,继续往后扫。
- 6指针 i 走到下标 1,值是 2。去表里查 2 之前在哪:表里还没有它。
- 72 是第一次出现,把它的下标 1 记进表里,继续往后扫。
- 8指针 i 走到下标 2,值是 3。去表里查 3 之前在哪:表里还没有它。
- 93 是第一次出现,把它的下标 2 记进表里,继续往后扫。
- 10指针 i 走到下标 3,值是 1。表里查到 1 上次在下标 0,这次距离是 3 − 0 = 3。
- 11距离 3 超过了 k=2,这一对太远不算。把 1 的「最后下标」更新成 3,继续往后扫。
- 12指针 i 走到下标 4,值是 4。去表里查 4 之前在哪:表里还没有它。
- 134 是第一次出现,把它的下标 4 记进表里,继续往后扫。
- 14指针 i 走到下标 5,值是 5。去表里查 5 之前在哪:表里还没有它。
- 155 是第一次出现,把它的下标 5 记进表里,继续往后扫。
- 16指针 i 走到下标 6,值是 6。去表里查 6 之前在哪:表里还没有它。
- 176 是第一次出现,把它的下标 6 记进表里,继续往后扫。
- 18指针 i 走到下标 7,值是 6。表里查到 6 上次在下标 6,这次距离是 7 − 6 = 1。
- 19距离 1 不超过 k=2,下标 6 和 7 这两个 6 挨得够近,条件满足,直接返回 true。
- 20找到了高亮的这一对相等数字,且距离不超过 k,所以答案是 true。
⚠️ 容易写错的地方
✗ 错:查到相等就返回,不看距离
✓ 对:必须同时满足 i − 上次下标 ≤ k
题目要的是「附近」的重复,不判距离会把离得很远的相等数也误判为 true
✗ 错:遇到相等不更新下标,沿用最早那次
✓ 对:每次都把下标覆盖成最新的 i
留最新下标才能让后面的数和「最近一次」比距离;留旧的会算出偏大的距离而漏判
✗ 错:用两层循环枚举所有数对
✓ 对:用哈希表把查询降到 O(1)
两层循环是 O(n²),数据一大就超时;哈希表把它降到 O(n)
完整代码(Python / C++ / Java)
Python
def containsNearbyDuplicate(nums, k):
last = {} # 值 -> 最后出现的下标
for i, x in enumerate(nums):
if x in last and i - last[x] <= k:
return True # 相等且距离够近
last[x] = i # 更新这个值的最新下标
return FalseC++
bool containsNearbyDuplicate(vector<int>& nums, int k){
unordered_map<int,int> last;
for (int i = 0; i < nums.size(); i++) {
int x = nums[i];
if (last.count(x) && i - last[x] <= k) return true;
last[x] = i;
}
return false;
}Java
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer,Integer> last = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int x = nums[i];
if (last.containsKey(x) && i - last.get(x) <= k) return true;
last.put(x, i);
}
return false;
}复杂度
时间
O(n)
指针 i 把数组扫一遍,每个数的查表和更新都是 O(1)
空间
O(min(n, 用到的不同值个数))
哈希表最多记下数组里出现过的不同数字
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 存在重复元素 II 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么哈希表里要存「最后一次」的下标,而不是第一次?+
因为我们关心的是「附近」的重复。后面的数要和最近一次的相同数字比距离,留最近的下标才能让距离最小、最可能满足 ≤ k。
能不能用滑动窗口集合来做?+
可以。维护一个大小不超过 k 的集合(窗口),i 进窗口前先看 x 在不在窗口里,在就返回 true;同时把超出窗口的元素移出。本质和哈希表记下标等价。
如果 k 是 0 会怎样?+
k=0 要求 |i−j|≤0,即同一个下标,不可能有两个不同下标满足,所以恒为 false。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 存在重复元素 II 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
把这道题真正拿下
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。