Description:
Given a string, find the length of the longest substring without repeating characters.
Example 1:
Input: "abcabcbb"
Output: 3
Explanation: The answer is "abc", which the length is 3.
Example 2:
Input: "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
Example 3:
Input: "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
思路:
题目要求最长无重复子串。
第一种,暴力求解:遍历字符串,每次寻找从当前字符往后延伸,直到末尾或者出现重复字符。中间需要用辅助hash保存已出现过的字符,时间复杂度为 O(n2) O ( n 2 ) ,空间复杂度为 O(k) O ( k ) ,k为字符集大小
第二种:滑动窗口法,用i,j指向窗口的前后下界,如果当前字符未出现在窗口,j后移,如果出现了,i后移。这里窗口用集合实现,判存复杂度为 O(1) O ( 1 ) 。总的时间复杂度为 O(2n)=O(n) O ( 2 n ) = O ( n ) ,最坏情况为每个字符都被访问两遍(分别作为窗口的头尾),空间复杂度为 O(k) O ( k )
算法实现如下:
class Solution(object):
# 滑动窗口法
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
slen = len(s)
if slen == 0:
return 0
i = j = 0
charlist = set()
maxlen = 0
while i < slen and j < slen:
# 如果尾字符出未现在集合中,加入集合,指针后移
if s[j] not in charlist:
charlist.add(s[j])
maxlen = max(maxlen, j - i + 1)
j += 1
else:
# 如果尾字符出现在集合当前,由于不知道出现在前面哪个位置,所以从前面依次移除字符。
charlist.remove(s[i])
i += 1
return maxlen
第三种,动态规划:利用已寻找的信息,用字典保存当前字符上一次出现的位置,
dp[j] = i 表示子串s[i…j]是以s[j]字符为结尾的最长无重复子串,那么有:
dp[0]=0
d
p
[
0
]
=
0
当s[j+1]不在s[i…j]中:
dp[j+1]=dp[j]
d
p
[
j
+
1
]
=
d
p
[
j
]
当s[j+1]在s[i…j]中:
dp[j+1]=上一个s[j+1]字符的位置
d
p
[
j
+
1
]
=
上
一
个
s
[
j
+
1
]
字
符
的
位
置
而判断s[j+1]是否在s[i…j]中,只需要比较上一个s[j+1]的位置是否大于i即可。
只需遍历一次字符串,因此时间复杂度为 O(n) O ( n ) ,空间复杂度为 O(k) O ( k )
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
slen = len(s)
if slen == 0:
return 0
chardict = dict()
maxlen = 0
last_start = -1
for i in range(slen):
# last_start表示即为dp[i-1]
last_start = max(last_start, chardict.get(s[i], -1))
maxlen = max(maxlen, i - last_start)
chardict[s[i]] = i
return maxlen