3. 无重复字符的最长子串
Origin: LeetCode 3
题目描述
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1: 输入: s = “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”。
示例 2: 输入: s = “bbbbb” 输出: 1
示例 3: 输入: s = “pwwkew” 输出: 3 解释: 因为无重复字符的最长子串是 “wke”。注意答案必须是子串的长度,“pwke” 是一个子序列,不是子串。
提示:
- 0 <= s.length <= 5 * 10
- s 由英文字母、数字、符号和空格组成
我的解法
function lengthOfLongestSubstring(s: string): number {
if (!s.length) return 0
const set = new Set<string>()
let left = 0
let maxLength = 0
for (let right = 0; right < s.length; right++) {
while (set.has(s[right])) {
set.delete(s[left])
left++
}
set.add(s[right])
maxLength = Math.max(maxLength, set.size)
}
return maxLength;
};8 组用例实际验证通过,含三个经典坑:"dvdf"(left 回退陷阱)、"abba"(重复字符在窗口左边界外)、"tmmzuxt"(重复字符已被移出窗口)。
亮点:Math.max(maxLength, set.size) 直接用 set.size 记录窗口大小,省掉了 right - left + 1 的区间计算——set 本身就是窗口内容的真实记录,窗口信息被自然复用。
解题思路(草稿)
滑动窗口——标准解法
窗口 [left, right] 内维护”无重复”这个不变量。right 每前进一格,如果新字符造成重复,left 收缩到重复字符消失为止。
function lengthOfLongestSubstring(s: string): number {
const window = new Set<string>()
let left = 0, maxLen = 0
for (let right = 0; right < s.length; right++) {
const c = s[right]
while (window.has(c)) {
window.delete(s[left])
left++
}
window.add(c)
maxLen = Math.max(maxLen, right - left + 1)
}
return maxLen
}关键点:
- 不变量:窗口内永远无重复。right 扩张可能破坏它,left 收缩恢复它。
- left 只前进不后退:这是滑动窗口 O(n) 的原因。right 走 n 步,left 最多也走 n 步,总操作 2n。
- Set 存的是什么:当前窗口内的字符。
window.has(c)判断的就是”新字符是否已在窗口里”。
暴力对照
暴力是枚举所有子串 O(n²) 每个子串再查重 O(n),共 O(n³)。滑动窗口的本质优化:重复的子串不再重新检查——[left, right-1] 无重复这个信息被复用了。
手推一遍 “abcabcbb”
right=0 'a': 窗口{a} max=1
right=1 'b': 窗口{a,b} max=2
right=2 'c': 窗口{a,b,c} max=3
right=3 'a': 重复!删 a,left=1 窗口{b,c,a}
right=4 'b': 重复!删 b,left=2 窗口{c,a,b}
right=5 'c': 重复!删 c,left=3 窗口{a,b,c}
right=6 'b': 重复!删 a,删 b,left=5 窗口{c,b}
right=7 'b': 重复!删 c,删 b,left=7 窗口{b}
max = 3
注意 left 收缩是逐个删,不是跳到目标位置——所以最坏还是 O(2n),均摊 O(1)。
优化变体:left 直接跳跃
用 Map 记每个字符最后出现的位置,left 可以直接跳:
const map = new Map<string, number>()
// ...left = Math.max(left, map.get(c)! + 1)但要注意 max 取旧位置的情况(字符在窗口外),需要 Math.max 防止 left 后退。Set 版逻辑更简单,面试写 Set 版足够。
复杂度
- 时间:O(n),left/right 各最多走 n 步
- 空间:O(min(n, 字符集大小)),窗口最多装下不重复的字符
关联
- 滑动窗口 - 模板总结
-
- 找到字符串中所有字母异位词 - 同模板的下一题
-
- 最小覆盖子串 - 滑动窗口困难版