Vvvrf / DSA.log← 返回全部笔记
LEETCODE 003Medium

无重复字符的最长子串

用滑动窗口维护一个始终合法的区间,并在右边界移动时更新答案。

窗口表示什么

[left, right] 始终表示一个没有重复字符的子串。右边界负责探索新字符,出现冲突时,左边界负责恢复窗口的合法性。

def lengthOfLongestSubstring(s: str) -> int:
    last_seen = {}
    left = 0
    answer = 0

    for right, char in enumerate(s):
        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

最容易错的地方

更新左边界时必须判断旧位置是否还在当前窗口中。否则,遇到 abba 时,最后一个 a 会让左边界错误地向后退。

if char in last_seen and last_seen[char] >= left:
    left = last_seen[char] + 1

滑动窗口识别信号

  • 答案来自连续区间;
  • 右边界扩张后可以快速判断是否合法;
  • 左边界右移能够恢复合法性;
  • 两个边界都不会向后退,因此总移动次数是线性的。

这道题的时间复杂度是 $O(n)$,额外空间取决于字符集大小。