无重复字符的最长子串问题解析
问题背景
LeetCode 438.找到字符串中所有字母异位词
无重复字符的最长子串问题是一个常见的字符串处理问题,要求找出给定字符串中不含有重复字符的最长子串的长度。
相关知识
在解决无重复字符的最长子串问题之前,需要了解以下关键知识点:
- 字符串:由字符组成的序列。
- 子串:字符串中连续的一部分字符组成的子序列。
滑动窗口
滑动窗口是解决一类子串或子数组问题的常用技巧。它通常用于寻找满足某种条件的子串或子数组。
基本思想是维护一个窗口,该窗口的大小可以动态调整,窗口内包含满足条件的元素,然后移动窗口的起始位置以寻找更多的满足条件的元素。滑动窗口的核心思想是通过调整窗口的位置,降低问题的复杂度。
在解决无重复字符的最长子串问题中,滑动窗口可以用来维护一个不含重复字符的子串。
问题介绍
给定一个字符串 s
,找出其中不含有重复字符的最长子串的长度。
问题示例
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。请注意,你的答案必须是子串的长度,“pwke” 是一个子序列,不是子串。
解题思路
解决无重复字符的最长子串问题的一种常用方法是使用滑动窗口(双指针法)。
具体步骤如下:
- 初始化左指针
left
和右指针rk
为 -1,并初始化最大子串长度ans
为 0,以及一个空的集合hash
用于存储字符。 - 遍历字符串
s
的每个字符,使用右指针rk
指向当前字符,同时将字符加入集合hash
中。 - 如果集合
hash
中已经包含了当前字符,说明出现了重复字符,需要将左指针left
右移,直到集合hash
不再包含重复字符。 - 在每次移动右指针
rk
后,计算当前子串的长度rk - left + 1
,并更新最大子串长度ans
。 - 重复步骤 2 到步骤 4,直到遍历完整个字符串
s
。
最终,ans
即为不含重复字符的最长子串的长度。
代码实现
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if s is None or len(s) == 0:
return 0
n = len(s)
rk, ans = -1, 0
hash = set()
for i in range(n):
if i != 0:
hash.remove(s[i-1])
while rk + 1 < n and s[rk + 1] not in hash:
hash.add(s[rk + 1])
rk += 1
ans = max(ans, rk - i + 1)
return ans
上述 Python 代码实现了滑动窗口法的思路。我们使用左指针 left
和右指针 rk
维护一个滑动窗口,集合 hash
存储窗口内的字符。通过遍历字符串 s
,在每次移动右指针 rk
后计算子串长度并更新最大子串长度 ans
。
时间和空间复杂度
- 时间复杂度:滑动窗口法的时间复杂度为 O(n),其中 n 是字符串
s
的长度。 - 空间复杂度:滑动窗口法使用了集合
hash
来存储窗口内的字符,空间复杂度为 O(k),其中 k 为字符集的大小,通常是常数级别。
结论
无重复字符的最长子串问题是一个常见的字符串处理问题,滑动窗口法是解决该问题的有效方法。希望本文对理解该问题的解决思路和实现有所帮助。