题目重点:维护当前窗口左端和每个字符最近下标,重复时只向右推进左端,在线性时间求最长连续无重复片段。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 输入是字符串,返回最长连续子串长度;空串为 0,字符按代码点区分大小写。
- 子串必须连续,不等于 q88 允许跳过字符的子序列。
- 题目未明确 Unicode/grapheme 规则,训练版按语言字符串迭代得到的字符单位处理。
解题路线
- 保持窗口 [left,right] 内无重复,lastSeen[ch] 记录 ch 最近一次位置。
- 处理 right 字符时,若其上次位置 ≥left,把 left 移到旧位置+1;否则 left 不动。更新最近位置和窗口长度最大值。
- left 只向右移动,每个 right 一次,因此 O(n)。正确性:更新后 [left,right] 是以 right 结尾的最长无重复窗口,较左的起点必包含重复字符。
手动走一遍
'abba':遇第二个 b 时 left 从 0 变 2;最后 a 的旧位置 0 已落在窗口外,left 不能退回 1,所以答案 2。'pwwkew' 最长为 'wke' 长 3,而跳过字符的 'pwke' 不算子串。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
"""Length of the longest contiguous substring without repeated characters."""
def longest_unique_substring_length(text: str) -> int:
last_seen = {}
left = 0
best = 0
for right, character in enumerate(text):
if character in last_seen and last_seen[character] >= left:
left = last_seen[character] + 1
last_seen[character] = right
best = max(best, right - left + 1)
return best
复杂度
n 个字符、最多 d 个不同字符:O(n) 时间、O(d) 字典空间。
易错点与追问
容易失分的边界
- 看见旧字符就无条件设 left=lastSeen+1,导致窗口左端倒退。
- 把子序列当子串。
- 用 set 清空整个窗口,反复扫描造成不必要的复杂度。
继续深挖
- 如何返回具体最早的最长子串而非长度?
- 输入是流且内存有限,最近位置表可否压缩?
- Unicode 组合字符按用户可见字符计数时如何改变分词?
