完整教程:Leetcode003——无重复字符的最长子串


一个派对组织者,正在一条热闹的街道上(字符串)邀请人们参加你的派对。但你的派对有一个严格的规定:就是想象一下,你不能有重复的人找出最多能连续邀请多少人而不违反规则。就是(无重复字符)。你的任务

派对的规则与挑战

  • 街道:字符串,比如 “abcabcbb”
  • 客人:每个字符代表一个人
  • 派对:当前邀请的子串
  • 规则:派对中不能有重复的客人
  • 目标:找到最长的不违反规则的派对规模

如何组织派对?滑动窗口法

你有两个助手:左指针右指针,他们就像派对的门口保安。还有一个签到表(哈希集合)来记录当前派对中的客人。

派对的进行过程

  1. 右指针(热情邀请者)从左到右沿着街道移动,邀请每个人加入派对。
  2. 左指针(冷静管理者)负责在出现重复时,请出最早加入的客人,直到重复消失。
  3. 签到表实时更新,确保没有重复客人。
  4. 你随时记录派对的最大人数。

以 “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),取较小值。

实践建议

  • 这种方法就像管理一个实时派对,确保总是最优状态。
  • 适用于任何字符串,包括数字、符号等。
  • 在实际编程中,这种滑动窗口技巧常用于解决子串问题。

下次遇到类似问题,记得想想这个派对故事!如果你能管理好这个派对,你就能解决很多字符串问题。

posted @ 2025-09-07 20:10  yfceshi  阅读(7)  评论(0)    收藏  举报