一、题目描述
给定一个字符串 s,请你找出其中不含有重复字符的最长子串的长度。
- 输入示例:
s = "abcabcbb" - 输出示例:
3 - 解释:因为无重复字符的最长子串是
"abc",所以其长度为 3。
二、解题思路:滑动窗口 + 哈希表
核心思想
这道题的经典解法是滑动窗口(双指针)+ 哈希表,时间复杂度 O (n),空间复杂度 O (min (m, n))(m 为字符集大小)。
-
双指针定义
left:窗口左边界,用来收缩窗口right:窗口右边界,用来扩展窗口- 窗口
[left, right]内始终保持无重复字符
-
哈希表作用
- 用哈希表(或数组)记录每个字符最后一次出现的位置
- 避免重复遍历,快速判断当前字符是否在窗口内重复
-
窗口维护规则
- 如果当前字符未出现过 → 扩展窗口(
right右移) - 如果当前字符已出现过 → 收缩窗口(
left移动到该字符上一次出现位置的下一位,保证窗口内无重复) - 每一步都计算当前窗口长度,更新最大长度
- 如果当前字符未出现过 → 扩展窗口(
三、代码实现(Python)
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
char_index = {} # 记录字符最近出现的位置
left = 0
max_len = 0
# 右指针遍历字符串
for right in range(len(s)):
char = s[right]
# 如果字符已出现过
if char in char_index:
# 更新当前字符的最新位置 ,防止 left 回退
left = max(left, char_index[char] + 1)
char_index[char] = right
# 计算当前窗口长度,更新最大值
max_len = max(max_len, right - left + 1)
return max_len
四、关键知识点讲解
1. 滑动窗口(Sliding Window)
滑动窗口是一种线性时间的双指针技巧,常用于处理子数组 / 子串问题:
- 本质:用两个指针动态维护一个区间,避免暴力枚举所有子串
- 优势:将 O (n²) 暴力解法优化到 O (n)
- 适用场景:最长 / 最短子串、子数组和、连续子数组等问题
2. 哈希表(Hash Table)优化
-
这里用字典
char_index存储{字符: 最后出现位置},查询时间 O (1) -
对比用
HashSet记录窗口内字符的版本:- HashSet 版:发现重复时需要逐个移动
left并删除字符,效率稍低 - 哈希表版:直接定位到重复字符的上一次位置,一步到位更新
left,更高效
- HashSet 版:发现重复时需要逐个移动
3. 边界处理细节
left = char_index[char] + 1:必须加 1,保证窗口内不再包含重复字符- 只有当重复字符的位置
>= left时才更新left,避免窗口左边界回退(比如字符在窗口外重复) - 窗口长度计算:
right - left + 1(因为区间是闭区间)
五、复杂度分析
- 时间复杂度:O(n),
right指针遍历字符串一次,left指针最多随right移动 n 次,总体线性时间 - 空间复杂度:O (min (m, n)),最多存储所有不重复字符,m 为字符集大小(如 ASCII 码为 128)