题目:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是"abc",所以其长度为 3。
讨论区的一个解法我认为挺好。思路是:
- 用哈希表保存<字母,索引+1>的键值对。重复的字母用对应的索引值覆盖掉旧索引。(这里的索引和之后的索引,其实是索引+1)
- 用left指向无重复字符串的开头那个字符的索引,初始化为0。
- 用length记录最长子串的长度,初始化为0
- 新建空字典
- 遍历字符串
- 判断当前遍历到的字符是否在字典中,如果不在,则length = max( length, j - left + 1),相当于求当前字符到无重复子串靠头的距离,就是无重复子串的长度。
- 如果当前字符在字典的键中,说明有子串重复了,但是并不知道重复的字符是否属于无重复字符串,记得我们使用的是left记录的无重复字符串的开头索引,用字典的值记录的是字符的index。如果已经在字典中存在的字符,那么这个字符的index如果下于left,说明不在无重复子串中,我们需要把length继续加一,还是用length = max( length, j - left + 1),这代表加1的功能,是因为j 加 1,left 不变。如果遍历到之前存在过的字符,且前一个存在的字符的index大于left,那就说明这个重复的字符就是在无重复子串中的,那么只能中断length的记录,即length不增加了,既然字符重复了,就该把left往后移动一个,即left = dict[s[j]],因为dict中记录的index是字符的index+1,所以这样赋值本质把后一位的index给了left,就是把无重复子串的开头变到遍历到的字符的前一个重复字符的后一个字符的位置。
- 最后不管该字符有没有重复,都把他和他的index+1加入到字典中。(对于重复的字符串来说,等于覆盖index)
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
dic = {}
left = 0
length = 0
for i in range(len(s)):
if (s[i] not in dic.keys()) or (dic[s[i]] < left):
length = max(length, i - left + 1)
else:
left = dic[s[i]]
dic[s[i]] = i + 1
return length
我认为这个方法的精髓就是在left和倒数第二行上。
对于重复的字符,把index覆盖掉,就是更新了重复字符在无重复子串的位置。比如,如果有一个字符"abcade",第二个‘a’就会把旧的键值对从{‘a’:1}到{‘a’:4}覆盖了,然后此时left应该还是0,那么不满足4<0,则更新left到1,1恰好就是前一个a这个字符的下一个字符的索引。
我自己的方法
可以说是很丑陋了。
max_length = 0
if(len(s)==1):
return 1
elif len(s)>1:
max_length =1
for i in range(len(s)-1):
a = s[i]
for j in range(i+1,len(s)):
if s[j] not in a:
a = a+s[j]
max_length = max([max_length,len(a)])
else:
break;
return max_length
就是普通的滑窗法。
执行用时 :1184 ms, 在所有 Python3 提交中击败了6.73%的用户
内存消耗 :14 MB, 在所有 Python3 提交中击败了5.01%的用户