Jiang's blog

每日一道算法之--无重复的最长的子字符串

Word count: 830Reading time: 3 min
2020/02/29 Share

无重复的最长的子字符串

力扣第3题:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/

3ykYNt.png

1 暴力解决

暴力方法就是将所有的肯恩列举出来,在会超过时间限制,这里就不列举了

2 滑动窗口

这道题是我第一道碰到的滑动窗口的题目,当时想了很久都想不出来,后来去看一一下别人的题解恍然大悟,滑动窗口确实是解决字符串问题的一非常好的方法

  • 滑动窗口的顾名思义就是可以滑动的数据结构,遍历整个字符串,当滑动窗口里没有该字符时,就将该字符加进滑动窗口

  • 当遇到有重复字符时,要将滑动窗口该字符前面的的字符(包括该字符)全部去除,然后在将该字符加进滑动窗口

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
# 集合可以保证唯一性
silde_win = set()
# 设置滑动窗口的值
left = 0
# 记录最长子串的长度
max_len = 0
# 记录当前的子串长度
cur_len = 0
for i in range(len(s)):
cur_len += 1
# 设置滑动窗口的值
while s[i] in silde_win:
silde_win.remove(s[left])
left += 1
cur_len -= 1
silde_win.add(s[i])
max_len = max(max_len, cur_len)
return max_len

2.1 复杂度分析

时间复杂度:遍历了一次数组,时间复杂度为$$0(N)$$, 但是每次滑动窗口的都有重复字符,如字符串为’aaaaaaaaaaaaaaaaaaa’,会浪费没必要的时间,但是均摊时间复杂度依然为$$O(N)$$

空间复杂度:用了集合,所以空间复杂度为$$O(N)$$

无重复最大子序_滑动1_.png

滑动窗口的优化

可以看到提交的成绩不是很理想,所以我一直在想着怎么优化,想到了几个优化方法

  • 如果字符串有相邻的子串,直接忽视
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
    if not s :return 0
    silde_win = set()
    left = 0
    max_len = 0
    cur_len = 0
    for i in range(len(s)):
    # 如果字符串有相邻的子串,直接忽视
    if i > 0 and s[i-1] == s[i]:
    silde_win = set()
    silde_win.add(s[i])
    left = i
    cur_len = 1
    continue
    cur_len += 1
    # 设置滑动窗口的值
    while s[i] in silde_win:
    silde_win.remove(s[left])
    left += 1
    cur_len -= 1
    silde_win.add(s[i])
    max_len = max(max_len, cur_len)
    return max_len

3y1Zs1.png

可以发现成绩有了提升,但不是很明显

  • 然后在看看我么你写的代码,silde_win这个数据结构其实是有很多操作的,话费了很多时间,换个思路想一想,我们能又能用更好地数据结构来代替这个集合呢,其实这个滑动窗口只是一个辅助的数据结构,只是用来暂时存储字符串的字串的,那为什么不直接用分片呢
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
if not s :return 0
# 设置滑动窗口的值
left = 0
# 记录最长子串的长度
max_len = 0
# 记录当前的子串长度
cur_len = 0
for i in range(len(s)):
if i > 0 and s[i-1] == s[i]:
left = i
cur_len = 1
continue
cur_len += 1
# 设置滑动窗口的值
while s[i] in s[left:i]:
left += 1
cur_len -= 1
max_len = max(max_len, cur_len)
return max_len

3yJm1e.png

相似题目

76.最小覆盖子串

159. 至多包含两个不同字符的最长子串

340. 至多包含 K 个不同字符的最长子串

CATALOG
  1. 1. 无重复的最长的子字符串
    1. 1.1. 1 暴力解决
    2. 1.2. 2 滑动窗口
    3. 1.3. 2.1 复杂度分析
    4. 1.4. 滑动窗口的优化
      1. 1.4.1. 相似题目