给定一个字符串,找出不含有重复字符的最长子串的长度。
示例:
给定 "abcabcbb"
,没有重复字符的最长子串是 "abc"
,那么长度就是3。
给定 "bbbbb"
,最长的子串就是 "b"
,长度是1。
给定 "pwwkew"
,最长子串是 "wke"
,长度是3。请注意答案必须是一个子串,"pwke"
是 子序列 而不是子串。
解题思路
首先想到的解决思路是先遍历整个字符串,然后对遍历到的每个字符后的字符做处理(检查是否有重复元素),我们通过建立一个空的字符串,如果检查的字符在这个空的字符串中没有的话,我们将他加入这个空字符串中,并且记录这个空字符串的长度。
class Solution:
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
maxLength = 0
for i,_ in enumerate(s): #这里没有使用range函数
count = 0
usedChar = str()
for j in s[i:]:
if j not in usedChar:
usedChar += j
count += 1
if maxLength < count:#这里没有使用max函数
maxLength = count
else:
break
return maxLength
上述代码中我没有使用注释中的做法,是因为那样做消耗的时间会增加很多(尤其这里如果使用max
函数操作会极大地增加时间消耗,但是有的时候使用max
函数速度会更快,暂时不清楚原因),大家可以自己测试一下。
另外,我们通过分析可以知道这个算法最差情况的时间复杂度是O(n^2)
级别的,这显然不是我们想看到的。我们分析一下这个算法的缺陷在哪?
p w w k e w
i
j
usedChar = pw
当j
移动到第二个w
时,这个时候j in usedChar
,那么我们跳出循环。接着
p w w k e w
i
j
usedChar = w
这个步骤其实是没有用的,因为去掉一个元素后,不可能比之前的元素更长了。我们可以直接跳到重复元素之后开始新的循环。
p w w k e w
i
j
usedChar = w
我们这里借用之前Leetcode 1:两数之和中使用hash
表的思想
class Solution:
"""
:type s: str
:rtype: int
"""
def lengthOfLongestSubstring(self, s):
start = maxLength = 0
usedChar = {}
for index, char in enumerate(s):
if char in usedChar and start <= usedChar[char]:
start = usedChar[char] + 1
else:
maxLength = max(maxLength, index - start + 1)
usedChar[char] = index
return maxLength
这种解法速度很快,时间复杂度是O(n)
级别,但是空间复杂度也是O(n)
级别。这也是我认为这个题目目前为止最精彩的回答!!!
当然这个问题,我们也可以使用Leetcode 209:长度最小的子数组中提到的滑动窗口思想。
class Solution:
"""
:type s: str
:rtype: int
"""
def lengthOfLongestSubstring(self, s):
l = 0
r = 0
maxLength = 0
s_len = len(s)
usedChar = [0] * 256 #通过符号表记录符号出现次数
while l < s_len:
if r < s_len and usedChar[ord(s[r])] == 0:
usedChar[ord(s[r])] += 1
r += 1
else:
usedChar[ord(s[l])] -= 1
l += 1
maxLength = max(maxLength, r - l)
return maxLength
这个解法虽然比前面的慢,但是空间复杂度是O(256)
级别,而时间复杂度同样是O(n)
级别。
该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!