题目简介:
给定一个字符串,返回它的最长子串,并且子串中没有重复字符。下面举例:
字符串一:"abcabcbb" 返回:3
字符串二:"bbbb" 返回:1
字符串三:"pwwkeww" 返回:3
需要注意是,子串的顺序是不能更改的,像字符串三中,"pwke"就不是符合题意得子串。
解法一:最长字符串匹配
按照惯例,小天每次都会先介绍一种简单方法,题目既然要求输出最长子串,那么最简单的做法就是从最大可能地子串长度开始,不断遍历整个字符串,知道找到满足条件的子串。
class Solution:
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
i = len(set(s))
n = len(s)
flag = True
while i > 0:
for j in range(n - i + 1):
sub = s[j: j + i]
if len(set(sub)) == i:
flag = False
break
if flag == False:
break
i -= 1
return i
解法一实际上还是一种暴力求解法,最差的情况下,尽管子串中出现过的字符数量为,但是却需要尝试所有的可能性。这道题LeetCode上基准测试耗时为444 ms。
解法二:一次匹配
对算法的优化无非从时间复杂度和空间复杂度上着手,这道题怎么降低到线性复杂度呢?小天这里为同学们提供一种思路:
class Solution:
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
sub = []
max_sub = 0
for c in s:
if c not in sub:
sub.append(c)
else:
for i in range(len(sub)):
if sub[i] == c:
break
if len(sub) > max_sub:
max_sub = len(sub)
sub = sub[i + 1:]
sub.append(c)
if len(sub) > max_sub:
max_sub = len(sub)
return max_sub
sub是当前时刻子串,每遍历到一个字符,如果不存在子串中,就添加至最后。如果存在,则截取sub在该字符之后的部分作为新的sub,当然,不要忘了添加该字符。解法二的主循环保证时间复杂度降至线性,基准测试上耗时为100ms。
解法二显然不是最优的,为找到字符在list类型上的index,实现有点复杂了。State of the Art解法用了一种字典格式存储当前子串,用begin和res两个指示符代替子串内的搜索。有兴趣的同学可以上LeetCode看一下!
总结:
python中的for关键词耗时比较大,在实现中尽可能避免。