1.题目描述
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
2.解题思路
解法一:
先不考虑代码怎么实现,如果给一个例子中的例子 "abcabcbb",让你手动找无重复字符的子串,该怎么找。博主会一个字符一个字符的遍历,比如 a,b,c,然后又出现了一个a,那么此时就应该去掉第一次出现的a,然后继续往后,又出现了一个b,则应该去掉一次出现的b,以此类推,最终发现最长的长度为3。所以说,需要记录之前出现过的字符出现的位置,所以可以使用 HashMap 来建立字符和其最后一次出现位置之间的映射。
窗口的右边界 i 就是当前遍历到的字符的位置,为了求出窗口的大小,需要一个变量 left 来指向滑动窗口的左边界,这样,如果当前遍历到的字符从未出现过,那么直接扩大右边界,如果之前出现过,那么就分两种情况,在或不在滑动窗口内,如果不在滑动窗口内,那么就没事,当前字符可以加进来,如果在的话,就需要先在滑动窗口内去掉这个已经出现过的字符了,去掉的方法并不需要将左边界 left 一位一位向右遍历查找,由于 HashMap 已经保存了该重复字符最后出现的位置,所以直接移动 left 指针就可以了。维护一个结果 res,每次用出现过的窗口大小来更新结果 res,就可以得到最终结果。
left 指向滑动窗口内无重复子串左边的起始位置的前一个,由于是前一个,所以初始化就是 -1,然后计算窗口长度的时候,直接用 i-left 即可,用来更新结果 res。
参考链接:https://www.cnblogs.com/grandyang/p/4480780.html
解法二:
另一种实现类似 leetcode438.找到字符串中所有字母异位词,当出现重复字符时,移动left
3.代码实现
解法一:
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
left=-1
res=0
hash={}
for i in range(len(s)):
if s[i] in hash and hash[s[i]]>left:
left=hash[s[i]]
hash[s[i]]=i
else:
hash[s[i]]=i
res=max(res,i-left)
return res
解法二:
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
if not s:
return 0
window = {}
left = 0
right = 0
res = 0
while right < len(s):
window[s[right]] = window.get(s[right],0)+1
right += 1
# 判断的是right-1,因为right已经加1了
while window[s[right-1]] > 1:
window[s[left]] -= 1
left += 1
res = max(res, right - left)
return res
解法三:
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
from collections import Counter
if not s:
return 0
window = {}
left = 0
right = 0
res = 0
while right < len(s):
if window.get(s[right],0) == 0:
window[s[right]] = window.get(s[right],0)+1
res = max(res, right - left + 1)
right += 1
else:
while window[s[right]] > 0:
window[s[left]] -= 1
left += 1
return res