⛅(day26)
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
0 <= s.length <= 5 * 104
s
由英文字母、数字、符号和空格组成示例 1:
输入: s = "abcabcbb"
输出: 3
说明: 因为无重复字符的最长子串是
"abc",所以其
长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
说明: 因为无重复字符的最长子串是
"b"
,所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
说明: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
题目分析:
看过例题我们可以知道题意要求我们寻找字符串s中连续且不重复的子字符串。需要注意这个字符串可以是空格,或者为空。
那么如何寻找这个连续且不重复的子字符串?
这里提供一个思路是放置指针若出现重复的字符则移动指针,计算更新最大子字符串来确定这个连续不重复子字符串的长度。
怎么理解呢?
以例3为例 s = "pwwkew"
我们先在字符第一个字符放置指针 i 和 j
接着将遍历字符串s,遍历的同时移动指针j,因为不重复的要求,所以我们将字符串s的字符s[j]以键值对的方式加入到字典dic中,其中键是s[j],值为指针j(也就是s[j]所在位置),这样我们就记录了已经出现过的字符。
如果后面不会遇见重复的字符(也就是遍历到的字符不在字典dic中)
那么最长的连续子字符串的长度就 = j - i
如果后面会遇到重复的字符(也就是遍历到的字符在字典dic中)
那么我们就需要先保存当前的最长子字符串,然后再移动指针i去找到下一个最长子字符串。
我们可以将这些”最长“子字符串添加到一个列表,然后使用max()函数找到最长子字符串即可。但是为了减少空间复杂度,提高运行速度,我们不使用列表。假设我们找到当前第一个最长子字符串s1,再移动指针后找到最长子字符串s2,接着又找到第3个最长子字符串s3,我们再找到第二个最长子字符串s2时,就将其与s1比较并取s1,s2最大值。如果最大值为s1,再将其与s3比较并取最大值,这样仅使用一个变量就可以不断更新储存最长子字符串。
那么指针i的移动方式是什么?
上面已经说明当后面不在遇到重复的字符时不需要移动指针i,(这里的”后面“可以理解为字符串s后续的一个片段)
所以我们现在讨论后面出现重复字符的情况。
因为后面出现重复字符那么i指针移动规则应该为 i = max(dic[s[j]], i)
dic[s[j]]表示该字符第一次出现所在字符串的位置
为什么i 指针的移动方式不是 i = dic[s[j]]?
我们的思路是找出两重复字符间的距离来求最长字符串,但是不能直接将i指针放置为dic[s[j]。
-----------------------------------
比如这种情况 s = ‘abba’。
dic = {‘a’:0,‘b’:1}
如果i = dic[s[j],那么当j遍历到第二个a时,i对应的值为0,j = 3,j - i = 3,答案错误。
所以我们需要使用 i = max(dic[s[j]], i),注意到两个a中间又两个b,那么j遍历到第二个b时b已出现再字典中,i指针移动,因为 i = max(dic[s[j]], i)此时的i就为1,所以当j遍历到最后的a时就有j-i=2答案正确。
--------------------------------------------------------------
代码实现
def lengthOfLongestSubstring(s):
dic = {}
i, ans = -1, 0
for j in range(len(s)):
if s[j] in dic:
i = max(dic[s[j]], i)
ans = max(ans, j - i)
dic[s[j]] = j
return ans
代码注释
def lengthOfLongestSubstring(self, s):
dic = {} # 字典,key是字符串中的字符,value是字符所在位置
i, ans = -1, 0 # i用来做start指针,ans用来记录最大长度
for j in range(len(s)): # j用来做end指针,遍历字符串中的每一个字符
if s[j] in dic: # 若s[j]在字典中,即出现重复字符,需要移动初始指针i
i = max(dic[s[j]], i) # 初始指针向右移动,取指针i和对应第一次出现字符位置最大值
ans = max(ans, j - i) # 更新最大长度,上次的长度,与更新后的长度取最大
dic[s[j]] = j # 更新j指针所指字符对应的值
return ans
这里为什么要初始化指针i为-1?
这是因为指针j开始时为0,如果指针i也初始化为零,那么当s = ‘a’只有单个字符时,j - i=0,解答出错。初始化i = -1就是针对s只有单个字符的情况。
今天就到这,明天见。
❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄end❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄❄