New Grad SWE · VO Coding

Microsoft LC3 最长无重复子串:最近位置滑动窗口

维护当前窗口左端和每个字符最近下标,重复时只向右推进左端,在线性时间求最长连续无重复片段。

题目重点:维护当前窗口左端和每个字符最近下标,重复时只向右推进左端,在线性时间求最长连续无重复片段。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 输入是字符串,返回最长连续子串长度;空串为 0,字符按代码点区分大小写。
  • 子串必须连续,不等于 q88 允许跳过字符的子序列。
  • 题目未明确 Unicode/grapheme 规则,训练版按语言字符串迭代得到的字符单位处理。

解题路线

  1. 保持窗口 [left,right] 内无重复,lastSeen[ch] 记录 ch 最近一次位置。
  2. 处理 right 字符时,若其上次位置 ≥left,把 left 移到旧位置+1;否则 left 不动。更新最近位置和窗口长度最大值。
  3. 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 组合字符按用户可见字符计数时如何改变分词?
✓已复制微信号!