跳至内容
返回

LeetCode 3 - 无重复字符的最长子串

发布于:  at  06:35 下午

题目

给定字符串 s,求最长的不含重复字符的连续子串长度。

示例:

解题思路

使用滑动窗口(双指针)维护一个无重复字符的窗口 [j..i],其中:

核心不变量:

  1. 窗口内没有重复字符
  2. 左指针 j 只会右移,不会左移

当遇到重复字符时,左指针需要跳到上次出现位置的下一位,但必须使用 max(j, map[ch]) 确保 j 不会倒退。

为什么必须用 max?

s = "abba" 为例:

 index: 0 1 2 3
 s:     a b b a

当 i=3 遇到第二个 ‘a’ 时:

代码实现

 import java.util.HashMap;
 ​
 class Solution {
     public int lengthOfLongestSubstring(String s) {
         // map: 存储每个字符最近一次出现位置的"下一位"
         HashMap<Character, Integer> map = new HashMap<>();
 ​
         // res: 记录目前找到的最长无重复子串长度
         int res = 0;
 ​
         // i: 右指针,遍历字符串
         // j: 左指针,标记当前无重复子串的起始位置
         for (int i = 0, j = 0; i < s.length(); i++) {
             char ch = s.charAt(i);
 ​
             // 如果当前字符已经在窗口中出现过
             // 更新左指针 j 到"上次出现位置的下一位"
             // 使用 max 确保 j 只会右移,不会倒退
             if (map.containsKey(ch)) {
                 j = Math.max(j, map.get(ch));
             }
 ​
             // 更新最长长度:当前窗口大小是 i-j+1
             res = Math.max(res, i - j + 1);
 ​
             // 记录当前字符的"下一位",为下次遇到该字符做准备
             map.put(ch, i + 1);
         }
 ​
         return res;
     }
 }

代码解释

  1. 初始化:创建 HashMap 存储字符位置,res 记录最大长度,双指针 i 和 j 初始为 0
  2. 右指针扩张:i 遍历整个字符串,每次取当前字符
  3. 处理重复:如果字符已存在,通过 max(j, map[ch]) 更新左指针
  4. 更新答案:每次计算当前窗口长度 i - j + 1,更新最大值
  5. 记录位置:将当前字符的下一位存入 map

速记

滑动窗口 + HashMap:右指针扩张,遇重复则左指针跳转,使用 max 防止左指针倒退。

注意点

  1. 左指针必须用 max:防止 j 倒退导致窗口包含重复字符
  2. map 存 i+1:存储下一位置而非当前位置,更新 j 时更方便
  3. 窗口长度计算i - j + 1,不要写错
  4. 空字符串处理:循环条件 i < s.length() 已处理,无需额外判断

复杂度分析


建议修改
在以下平台分享此文章:

下一篇
LeetCode 160 - 相交链表