题目重点:从 CS 面经的明确题名推导 lastSeen 与左边界更新,验证空串、重复密集和字符集限制。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版返回长度,不返回实际子串;字符以语言字符串迭代单位处理。
- 若题目按 Unicode grapheme 而非 code point 计字符,需先做分段;题目未说明。
解题路线
- 窗口 [left,right] 保证无重复,lastSeen[char] 存该字符最后位置。
- 遇重复且 lastSeen≥left 时把 left 跳到 lastSeen+1;否则 left 不变,绝不能向左回退。
- 每步更新 lastSeen 与最大窗口长;证明 right 每次+1,left 最多前进 n 次,所以 O(n)。
- 用 abba 干跑:最后一个 a 的旧位置在窗口左侧,left 不能从 2 回到 1。
手动走一遍
abba:r=0/1 窗口 ab 长 2;r=2 遇 b,left=2;r=3 遇 a,但旧 a 位置 0<left,窗口 ba 长 2,答案 2。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def longest_unique_length(text):
left = 0
last_seen = {}
answer = 0
for right, char in enumerate(text):
if char in last_seen and last_seen[char] >= left:
left = last_seen[char] + 1
last_seen[char] = right
answer = max(answer, right - left + 1)
return answer
复杂度
O(n) 时间、O(min(n,字符集大小)) lastSeen 空间;若字符集固定且小可用定长数组。
易错点与追问
容易失分的边界
- left=lastSeen+1 而不取不回退条件。
- 把子序列当子串。
- 遇重复就清空整个窗口,导致退化或错误。
- 忽略字符集限制。
继续深挖
- 若还要返回最早的最长子串?
- 流式 chunk 如何维持状态?
- Unicode grapheme 怎样处理?
