必须拿起的最小连续卡牌数
给你一个整数数组 `cards` ,其中 `cards[i]` 表示第 `i` 张卡牌的 值 。如果两张卡牌的值相同,则认为这一对卡牌 匹配 。
返回你必须拿起的最小连续卡牌数,以使在拿起的卡牌中有一对匹配的卡牌。如果无法得到一对匹配的卡牌,返回 `-1` 。
示例 1:
输入:cards = [3,4,2,3,4,7] 输出:4 解释:拿起卡牌 [3,4,2,3] 将会包含一对值为 3 的匹配卡牌。注意,拿起 [4,2,3,4] 也是最优方案。
示例 2:
输入:cards = [1,0,5,3] 输出:-1 解释:无法找出含一对匹配卡牌的一组连续卡牌。
提示:
- `1 5`
- `0 6`
这练习的关键不是“找任意重复”,而是“找同值卡牌的最短距离”。
设同一个值 `x` 在数组中的出现下标依次为 `p1 < p2 < ... < pk`,那么包含一对匹配卡牌的最短连续区间,一定来自某两个相同值位置之间的最小间隔。 因此,我们只需要在遍历时记录每个值“最近一次出现的位置”即可。
做法: 1. 用哈希表 `last` 记录每个值上一次出现的下标。 2. 从左到右扫描数组。 3. 当当前值 `x` 之前出现过时,用当前下标 `i` 和上次下标 `last[x]` 计算区间长度 `i - last[x] + 1`,更新答案。 4. 不断更新 `last[x] = i`。 5. 如果最后答案没更新过,返回 `-1`。
为什么正确: - 对于某个值的多次出现,最短匹配区间一定对应“相邻两次出现”之一。 - 因此只需比较“当前出现”和“最近一次出现”的距离,不会漏掉最优解。 - 单次遍历即可得到全局最小值。
复杂度: - 时间复杂度:`O(n)` - 空间复杂度:`O(n)`,用于哈希表记录下标
易错点: - 把答案写成 `i - last[x]`,忘记加 1。 - 只记录是否出现过,而不记录最近位置,导致无法得到最短区间。 - 没有重复时要返回 `-1`。 - 重复值可能很多次,必须持续更新最近位置,否则会错过更短答案。
出练习者可能追问: - 为什么只记录最近一次出现位置就够了? - 如果要返回具体区间 `[l, r]` 而不只是长度,怎么改? - 如果数组是流式输入,如何在线维护答案?
python
from typing import List
class Solution:
def minimumCardPickup(self, cards: List[int]) -> int:
last = {}
ans = float('inf')
for i, x in enumerate(cards):
if x in last:
ans = min(ans, i - last[x] + 1)
last[x] = i
return -1 if ans == float('inf') else ans高质量答案要覆盖四点:第一,识别本质是“同值最短距离”而不是复杂窗口维护;第二,用哈希表记录最近出现位置,一次遍历即可;第三,正确说明为什么只看最近一次出现不会漏解,因为同值多次出现的最短区间一定来自相邻出现;第四,明确复杂度 `O(n)` / `O(n)` 和边界情况(无重复、相邻重复、重复很多次)。 常见错误包括:把答案少算 1、只记是否出现过、不更新最近位置、写成双重循环超时。 出练习者常追问:为什么是最近一次而不是任意一次?能否返回区间下标?如果是在线数据流怎么做?如果值域很大或要支持动态删除怎么扩展?
- 为什么只记录最近一次出现位置就够了?
- 如果要返回最短区间的左右端点,怎么改代码?
- 如果 cards 是流式输入,如何在线维护答案?