← 返回编程题库
coding-longest-substring-no-repeat简单免费版2000ms未尝试

无重复字符的最长子串

Longest Substring Without Repeating Characters

开始编码

行情数据工程师在扫一段 tick 流,想知道字符串 s 中「最长的连续不重复字符段」是多长。这是滑动窗口最经典的原型:上游可能是订单流字符串中最长的不重复符号段、滚动配置日志里最长的不重复策略序列、会话 ID 中最长的非重复段。这些下游问题的骨架都是同一个:双指针 + 哈希表。

请实现 solution(s: str) -> int,返回 s最长不含重复字符的子串的长度。空字符串返回 0;全部相同字符的字符串返回 1;全部互不相同的字符串返回 len(s)

示例solution("abcabcbb") 返回 3 —— 最长不重复子串是 "abc"(下标 0..2)。到下标 3 时新来的 'a' 与位置 0 的 'a' 重复,窗口被迫前移;后续整段都在轮换 abc,最长仍是 3。solution("bbbbb") 返回 1 —— 任何扩展都会重复,窗口始终为 1。solution("pwwkew") 返回 3 —— 答案是 "wke"(下标 2..4),而不是子序列 "pwke"(注意:子串要求连续)。

朴素的 O(n²) 解法是「枚举每个起点 i,向右走到第一个重复字符」,能 AC 但浪费:每次重置起点都把右端的工作丢掉了。滑动窗口的关键是让两个指针都只向前不回头:维护 left(窗口起点)和 last_seen[c](字符 c 上次出现的下标,未出现则不在表中)。每个 right 进入时,若 last_seen[s[right]] >= left,说明上次出现就在窗口里,直接把 left 跳到 last_seen[s[right]] + 1 越过那个旧位置即可。max(left, last_seen[c] + 1) 这一步保护了「窗口左端单调不减」的性质——如果省掉 max,被旧的(已经离开窗口的)last_seen 一拽 left 就倒退了,不变量当场破。整体复杂度 O(n)(双指针均摊),哈希表 O(min(n, |alphabet|))。

约束条件

  • 0 ≤ len(s) ≤ 100000
  • 字符可以是任意 Unicode;测试只使用 ASCII 字母数字(及少量常见标点/空格)
  • 空字符串返回 0
  • 目标复杂度:O(n) 时间,O(min(n, |alphabet|)) 额外空间

样例

Case 1 · classic abcabcbb

输入: ["abcabcbb"]

期望: 3

最长不重复子串是 "abc"(下标 0..2),长度 3。到下标 3 的 'a' 与位置 0 重复,窗口被迫前移;之后整段都在 a/b/c 轮换,无法超过 3。

Case 2 · all same — bbbbb

输入: ["bbbbb"]

期望: 1

全部相同字符。窗口每扩展一次就立即遇到重复,所以最长不重复子串永远是单个字符,长度 1。

Case 3 · pwwkew — answer is wke not pwke

输入: ["pwwkew"]

期望: 3

答案是 "wke"(下标 2..4),不是 "pwke"——子串必须连续,子序列不算。注意 max(left, last_seen['w']+1) 在这里至关重要。

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · classic abcabcbb

输入: ["abcabcbb"]

期望: 3

最长不重复子串是 "abc"(下标 0..2),长度 3。到下标 3 的 'a' 与位置 0 重复,窗口被迫前移;之后整段都在 a/b/c 轮换,无法超过 3。

Case 2 · all same — bbbbb

输入: ["bbbbb"]

期望: 1

全部相同字符。窗口每扩展一次就立即遇到重复,所以最长不重复子串永远是单个字符,长度 1。

Case 3 · pwwkew — answer is wke not pwke

输入: ["pwwkew"]

期望: 3

答案是 "wke"(下标 2..4),不是 "pwke"——子串必须连续,子序列不算。注意 max(left, last_seen['w']+1) 在这里至关重要。