LeetCode 第3题 无重复字符的最长子串(滑动窗口(双指针)+ HashSet)

📅 2026/7/31 11:59:24 👁️ 阅读次数 📝 编程学习
LeetCode 第3题 无重复字符的最长子串(滑动窗口(双指针)+ HashSet)

一、核心算法思想

采用滑动窗口(双指针)+ HashSet,时间复杂度 \(O(n)\)。

  1. 定义窗口区间 \([i,rk]\):代表当前正在考察、无重复字符的连续子串;
  2. i:窗口左边界(外层循环遍历);rk:窗口右边界,只会向右移动,不回退
  3. HashSet 集合occ:实时保存当前窗口内部所有字符,快速判断字符是否重复;
  4. 流程:
    • 左边界i右移时,将移出窗口的字符从集合删除;
    • 在不重复前提下,尽可能向右扩张右边界 rk;
    • 每次扩张停止后,计算窗口长度,更新全局最长长度答案ans

区分概念:子串必须连续;子序列可以不连续。

二、完整带注释代码

class Solution { public int lengthOfLongestSubstring(String s) { // occ = occurrence,存储当前滑动窗口内的字符 Set<Character> occ = new HashSet<>(); int n = s.length(); int rk = -1, ans = 0; // rk右指针初始-1;ans=answer保存最终结果 for(int i = 0; i < n; i++){ if(i != 0){ // 左边界右移,把离开窗口的字符移除集合 occ.remove(s.charAt(i-1)); } // 右边界持续扩张:下一个字符不越界、且窗口不存在该字符 while(rk + 1 < n && !occ.contains(s.charAt(rk + 1))){ occ.add(s.charAt(rk + 1)); rk++; } // 更新最长子串长度 ans = Math.max(ans, rk - i + 1); } return ans; } }

三、实例运行推演

输入:s = "abcabcbb"

i (左边界)操作rk窗口\([i,rk]\)occ 集合当前窗口长度ans 最大值
i=0i=0 无需 remove;持续右扩 rk2[0,2]{a,b,c}3ans=3
i=1删除 s [0] 字符 a;右扩 rk3[1,3]{b,c,a}3ans=3
i=2删除 s [1] 字符 b;右扩 rk4[2,4]{c,a,b}3ans=3
i=3删除 s [2] 字符 c;右扩 rk5[3,5]{a,b,c}3ans=3
i=4删除 s [3] 字符 a;无法继续右扩5[4,5]{b,c}2ans=3
i=5删除 s [4] 字符 b;右扩 rk6[5,6]{c,b}2ans=3
i=6删除 s [5] 字符 c;无法继续右扩6[6,6]{b}1ans=3

最终返回 ans = 3

四、关键语法与内置方法、基础类型 & 包装类积累

1. String 内置方法

  1. s.length():获取字符串长度,必须带括号;数组长度写法arr.length(无括号)
  2. s.charAt(index):String 内置方法,根据下标获取对应字符;⚠️方法名全小写charAt,禁止写成CharAt

2. Java 基础类型与对应包装类

核心规则:Java 中Set、List、Map等集合泛型不支持基础数据类型,必须使用包装类。支持自动装箱、自动拆箱,无需手动转换。

基础类型(基本类型)对应包装类刷题场景示例
byteByteSet<Byte>
shortShortMap<Short,String>
intIntegerSet<Integer>(两数之和、最长连续序列高频)
longLongMap<Long,Integer>
floatFloat极少用到
doubleDouble极少用到
booleanBooleanSet<Boolean>
charCharacter本题Set<Character>

3. HashSet 常用方法

  • occ.add():字符加入集合
  • occ.remove():删除指定字符
  • occ.contains():判断字符是否存在集合内

4. 通用工具方法

Math.max(a,b):返回两个数字中较大的值,用于更新最长长度

五、高频易错点汇总

  1. 大小写错误s.CharAt()❌ 正确:s.charAt()
  2. 缺少调用对象:不能单独写charAt(),必须写成s.charAt(下标)
  3. 混淆lengthlength():字符串不要漏写括号
  4. 逻辑误区:不要一次性把全部字符放入集合;集合occ只保存当前窗口内字符
    • 窗口扩张 → add;窗口左移收缩 → remove;保持集合与窗口内容同步
  5. rk 初始值设为-1:窗口初始为空,保证第一轮循环可以访问下标 0 的字符
  6. if(i != 0)判断:i=0 是第一轮,窗口左侧没有移出元素,无需执行 remove

六、变量名称释义(刷题通用简写)

  • occ:occurrence,窗口内已经出现的字符集合
  • rk:right index,滑动窗口右指针
  • i:滑动窗口左指针
  • ans:answer,保存最终答案(最长无重复子串长度)