题目:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
输入:“eeydgwdykpv”
输出:7 (‘gwdykpv’)
思路:
遍历字符串,需要的变量:
max_len : 记录最长的子串长度
str_dict :存储不重复的字符及字符所在的下标,为了判断字符是否重复
one_max: 记录每次循环的最长字串
start : 记录 最长字串开始的位置,即 遇到重复的字符就返回前一个出现的位置的下 一个位置开始
解释 : 为什么 if有两个判断:
if s[i] in str_dict and str_dict[s[i]] >= start:
比如输入:“abba”
目的输出:2
如果不加后面的判断 则会输出3,即 当碰到第二个a时,又会从第一个b的位置开始判断,但是此时start即无重复字符开始的位置在第二个b即index是2的位置,已经判断过一遍了,会造成结果偏大。
判断过程如下,主要问题出在i=3的时候
i=0
one_max=1
str_dict={‘a’: 0}
max_len=1
i=1
one_max=2
str_dict={‘a’: 0, ‘b’: 1}
max_len=2
i=2
start=2
one_max=1
str_dict={‘a’: 0, ‘b’: 2}
max_len=2
i=3
start=1
start 上一步是2 此时又返回去了
one_max=3
str_dict={‘a’: 3, ‘b’: 2}
max_len=3
注意 : 如果面试官要求输出的是字符串,而不是数字,则根据start 即最长字符串开始的位置,及max_len 最长字串长度,切片原字符串即可
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
# 存储历史循环中最长的子串长度
max_len = 0
# 判断传入的字符串是否为空
if s is None or len(s) == 0:
return max_len
# 定义一个字典,存储不重复的字符和字符所在的下标
str_dict = {}
# 存储每次循环中最长的子串长度
one_max = 0
# 记录最近重复字符所在的位置+1
#即 如果碰到重复字符,要从上一次出现位置的下一个位置开始记录
start = 0
for i in range(len(s)):
# 判断当前字符是否在字典中和当前字符在字典中的下标是否大于等于最近重复字符的所在位置
#如果没有第二个判断条件 输出结果会偏大
if s[i] in str_dict and str_dict[s[i]] >= start:
# 记录当前字符的值+1
start = str_dict[s[i]] + 1
# 在此次循环中,最大的不重复子串的长度
one_max = i - start + 1
# 把当前位置覆盖字典中的位置
str_dict[s[i]] = i
# 比较此次循环的最大不重复子串长度和历史循环最大不重复子串长度
max_len = max(max_len, one_max)
return max_len
第二种方法:
# 方法二
st = {}
start, max_len = 0, 0
for i in range(len(s)):
if s[i] in st:
#下面两行代码相当于 第一种方法中的if的两个判断
#start 要取两个中的大值,防止判断过的一遍再判断一段,使输出结果偏大
start= max(st[s[i]]+1, start)
max_len = max(max_len, i - start+ 1)
st[s[i]] = i
return max_len;
滑动窗口思想
其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!
如何移动?
我们只要把队列的左边的元素移出就行了,直到满足题目要求!
一直维持这样的队列,找出队列出现最长的长度时候,求出解!
时间复杂度:O(n)O(n)
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s :
return 0
left = 0
lookup = set()
max_len = 0
cur_len = 0
n = len(s)
for i in range(n):
cur_len += 1
while s[i] in lookup:
lookup.remove(s[left])
left += 1
cur_len -= 1
if cur_len > max_len :
max_len = cur_len
lookup.add(s[i])
return max_len