LeetCode 3. 无重复字符的最长子串(中)& 剑指offer 面试题48. 最长不含重复字符的子字符串(中)
队列、滑动窗口,面试官期待应聘者能够用基于循环的代码来避免不必要的重复计算。
题目
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
测试用例
功能测试(包含多个字符的字符串;只有一个字符的字符串;所有字符都唯一的字符串;所有字符都相同的字符串)。 特殊输入测试(空字符串)。
本题考点
考查应聘者用动态规划分析问题的能力。应聘者能够熟练应用动态规划分析问题是解答这道面试题的前提。 考查应聘者对递归及时间效率的理解。如果只是能够把递归分析转换为递归代码,则应聘者不一定能够通过这道题的面试。面试官期待应聘者能够用基于循环的代码来避免不必要的重复计算。
示例
1 |
|
1 |
|
1 |
|
提示:s.length <= 40000
考察知识点
队列、滑动窗口
核心思想
滑动窗口
遍历字符串,找到不重复的部分,记录下来,输出最长的那一个。

动态规划
- 首先定义函数 \(f(i)\) 表示以第 \(i\) 个字符为结尾的不包含重复字符的子字符串的最大长度。初始化 \(f(0) = 1\)。
- 如果第 \(i\) 个字符在之前没有出现过,那么 \(f(i) = f(i) + 1\)。
- 如果第 \(i\) 个字符在之前已经出现过,那么先计算第 \(i\) 个字符距离它上次出现在字符串中的位置的距离,并记为 \(d\)。
- 当 \(d <= f(i-1)\) 时,说明第 \(i\) 个字符上次出现在 \(f(i-1)\) 对应的最长子字符串之中。同时这也意味着在第 \(i\) 个字符出现两次所夹的子字符串中再也没有其他重复的字符了。所以,此时 \(f(i) = d\)。
- 当 \(d>f(i-1)\) 时,说明第 \(i\) 个字符上次出现在 \(f(i-1)\) 对应的最长子字符串之前,因此仍然有 $ f(i)=f(i-1)+1$。
以 arabcacfr
为例:
更新选择
Update Type | |
---|---|
0 | \(f(0) = 1\) |
1 | \(f(i) = f(i) + 1\) |
2 | \(f(i) = d\) |
运算过程
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
char | a | r | a | b | c | a | c | f | r |
\(d\) | \ | \ | 2 | \ | \ | 3 | 2 | \ | 7 |
compute \(d\) | \ | \ | 2-0 | \ | \ | 5-2 | 6-4 | \ | 8-1 |
\(d <= f(i-1)\) | \ | \ | True | \ | \ | True | True | \ | False |
Update Type | 0 | 1 | 2 | 1 | 1 | 2 | 2 | 1 | 1 |
\(f(i)\) | 1 | 2 | 2 | 3 | 4 | 3 | 2 | 3 | 4 |
由上表可知, arabcacfr
中最长不含重复的子字符串为 rabc
和 acfr
, 长度为4。
状态转移方程为 \[ f(i)=\begin{cases} 0, \quad i = 0 \\ f(i-1) + 1, \quad d > f(i-1) \\ d,\quad d \leq f(i-1) \end{cases} \]
Python代码
- 滑动窗口
1 |
|
- 滑动窗口的另一个版本
1 |
|
- 动态规划
1 |
|
类似问题
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!