一、题目链接
https://leetcode.com/problems/longest-substring-without-repeating-characters/
二、解答
2.1 解法一,暴力求解
直接使用暴力方法,遍历所有可能的子串,并判断是否有重复的字符,当没有重复的字符时,计算其长度,然后取最长的字符串的长度即为最后的结果。
时间复杂度:\(O(N^3)\),N
为字符串的长度。 空间复杂度:我认为是 \(O(1)\),因为每一次 check,需要 128
个空间,这是一个常数单位。但是官方教程说是 O(min(m, n)),其中 m 是
128,n 是字符串的长度,我认为应该是错误的。
2.2 滑动窗口
直接看代码
这里主要的思想是利用 left 和 right 这两个指针,
- 先固定 left 指针,然后滑动 right 指针,
- 如果在 left 到 right 之间的子串中出现了重复的字符,那么,这时就固定
right 指针,
- 然后移动左指针,直到 left 到 right 之间的子串中没有重复的字符。
这里有一个 Python 函数要说明一下,
- ord(): Return the Unicode code(ASCII code) point for a one-character
string.
时间复杂度:\(O(N)\),left 指针和
right 指针在最坏情况下,总计会遍历字符数组两遍。
空间复杂度:同解法一的空间复杂度。
2.3 解法三 滑动窗口优化
直接看代码
使用字典的版本
说一下 line8 和 line9 代码的含义,这里是判断 j 指向的字符是否在 mp
字典中,如果在,说明之前出现过了这个字符,但是,出现过的字符有两种情况
- 第一种,重复的字符在索引 i 到 j(不含 j)之间,那么 line9
这行代码就会把 i 指针移动到 mp[s[j]] 位置处(注意 line11
这行代码),
- 第二种,重复的字符在索引 i 之前出现,这个对索引 i 到索引 j
之间的子串没有影响,因而,line9 执行完之后 i 的值不变。
使用列表的版本
这里的 line10 和 line11 两行代码和上面的使用字典的代码的 line8 和
line9 两行代码的作用相同。
时间复杂度:\(O(N)\)。
空间复杂度:我认为还是 \(O(1)\)。其实争执这个没什么意义。
三、完整代码