3. 无重复字符的最长子串
- 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例:
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
思路1:切片实现滑动窗口(时间复杂度 )
定义一个滑动窗口列表,遍历字符串:
若字符不在窗口中,则添加,扩展窗口;
若字符已经在窗口中,则将窗口先缩减到窗口列表中字符出现位置的下一字符处,再添加当前字符,保证窗口列表中无重复字符。
代码实现1:
class Solution(object):
def lengthOfLongestSubstring(self, s: str) -> int:
if not s:
return 0
window = [] # 滑动窗口列表
max_length = 0 # 最长串长度
for c in s:
# 如果字符不在滑动窗口中,则直接扩展窗口
if c not in window:
window.append(c)
# 如果字符在滑动窗口中,则
# 1. 从窗口中移除重复字符及之前的字符串部分,新字符串即为无重复字符的字符串
# 2. 再扩展窗口
else:
window = window[window.index(c) + 1:]
window.append(c)
# 更新最大长度
max_length = max(len(window), max_length)
return max_length
思路2:使用哈希表优化滑动窗口(时间复杂度 )
定义窗口左端变量 left 并设为-1,窗口长度为当前遍历到的值 - left。
使用 enumerate(s) 遍历索引及对应的字符串,使用哈希表存放映射关系,可能有三种情况:
- 哈希表中没有当前字符:直接向哈希表中添加映射关系,判断当前窗口长度是否大于最大长度,若是则更改最大长度为当前窗口长度;
- 哈希表中已经有当前字符,原有字符包含在窗口中:先将窗口左端变量left移动到原有字符位置(如图红色括号),再更改字符索引为当前索引值,即 {‘b’: 2};
- 哈希表中已经有当前字符,原有字符不包含在窗口中:直接向哈希表中更改映射关系(如字符a),判断当前窗口长度是否大于最大长度,若是则更改最大长度为当前窗口长度。
因为1、3操作相同,可将2作为if条件,1、3作为else条件。
代码实现2:
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
hash_map = {}
max_len = 0
left = -1
for i, c in enumerate(s):
if c in hash_map and hash_map.get(c) > left:
left = hash_map.get(c)
hash_map[c] = i
else:
hash_map[c] = i
max_len = max(max_len, i-left)
return max_len