完整教程:Leetcode003——无重复字符的最长子串
一个派对组织者,正在一条热闹的街道上(字符串)邀请人们参加你的派对。但你的派对有一个严格的规定:就是想象一下,你不能有重复的人找出最多能连续邀请多少人而不违反规则。就是(无重复字符)。你的任务
派对的规则与挑战
- 街道:字符串,比如 “abcabcbb”
- 客人:每个字符代表一个人
- 派对:当前邀请的子串
- 规则:派对中不能有重复的客人
- 目标:找到最长的不违反规则的派对规模
如何组织派对?滑动窗口法
你有两个助手:左指针和右指针,他们就像派对的门口保安。还有一个签到表(哈希集合)来记录当前派对中的客人。
派对的进行过程
- 右指针(热情邀请者)从左到右沿着街道移动,邀请每个人加入派对。
- 左指针(冷静管理者)负责在出现重复时,请出最早加入的客人,直到重复消失。
- 签到表实时更新,确保没有重复客人。
- 你随时记录派对的最大人数。
以 “abcabcbb” 为例,看看派对如何进展
- 初始状态:派对为空,左指针在起点,右指针开始邀请。
- 邀请
a:签到表{a},当前人数 1,最大人数 1 - 邀请
b:签到表{a, b},当前人数 2,最大人数 2 - 邀请
c:签到表{a, b, c},当前人数 3,最大人数 3 ← 暂时最佳
- 邀请
- 遇到重复:右指针邀请第4个客人
a,但a已在派对中!- 左指针开始请出客人:先请出
a,签到表变为{b, c} - 现在
a不再重复,邀请新a,签到表{b, c, a},人数 3
- 左指针开始请出客人:先请出
- 继续邀请:右指针移动
- 邀请
b:但b已在派对中!左指针请出b(最早加入的),签到表变为{c, a},然后邀请b,签到表{c, a, b},人数 3 - 邀请
c:重复!左指针请出c,签到表变为{a, b},然后邀请c,签到表{a, b, c},人数 3 - 邀请
b:重复!左指针请出a(因为a是最早的),签到表变为{b, c},但b还在,继续请出b,签到表变为{c},然后邀请b,签到表{c, b},人数 2 - 邀请
b:重复!左指针请出c,签到表变为{b},但b还在,请出b,签到表变为空,然后邀请b,签到表{b},人数 1
- 邀请
- 最终结果:最大人数始终是 3,故而答案是 3。
Java代码搭建:派对管理系统
import java.util.HashSet;
import java.util.Set;
class Solution
{
public int lengthOfLongestSubstring(String s) {
Set<
Character> set = new HashSet<
>();
// 签到表
int left = 0;
// 左指针(开始请出的位置)
int maxLength = 0;
// 记录最大人数
// 右指针逐个邀请客人
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
// 当前客人
// 如果当前客人已经在派对中,左指针开始请出客人直到重复消失
while (set.contains(c)) {
set.remove(s.charAt(left));
// 请出最早加入的客人
left++;
// 左指针右移
}
set.add(c);
// 邀请当前客人加入派对
maxLength = Math.max(maxLength, right - left + 1);
// 更新最大人数
}
return maxLength;
}
}
为什么这个方法高效?
- 时间复杂度 O(n):每个客人最多被邀请和请出各一次,于是总处理次数是 2n,即 O(n)。
- 空间复杂度 O(min(n, m)):签到表的大小取决于字符集的大小(m)或字符串长度(n),取较小值。
实践建议
- 这种方法就像管理一个实时派对,确保总是最优状态。
- 适用于任何字符串,包括数字、符号等。
- 在实际编程中,这种滑动窗口技巧常用于解决子串问题。
下次遇到类似问题,记得想想这个派对故事!如果你能管理好这个派对,你就能解决很多字符串问题。

浙公网安备 33010602011771号