LeetCode 003. 无重复字符的最长子串 - 滑动窗口与哈希表详解

一、文章标题

LeetCode 003. 无重复字符的最长子串 - 滑动窗口与哈希表详解

二、文章内容

1. 题目概述
2. 文章目录

目录

  1. 题目概述
  2. 解题思路
  3. 算法详解
    • 3.1 [解法一:暴力枚举 + 去重检查](#解法一:暴力枚举 + 去重检查)
    • 3.2 [解法二:滑动窗口(HashMap 下标跳跃)](#解法二:滑动窗口(HashMap 下标跳跃))
  4. 解法对比
  5. 最优解推荐
3. 解题思路
  • 问题分析:
    • 输入:一个字符串 s(可包含字母、数字、符号等)。
    • 输出:s 中不含重复字符的最长子串的长度(整数)。
    • 约束:子串必须连续;字符一旦重复,需移动左边界重新保持无重复。
  • 核心难点:
    • 如何在扫描过程中高效检测并维护"无重复"的窗口。
    • 当右侧遇到重复字符时,如何快速将左指针跳到正确位置,避免一个个挪动导致退化为 O(n^2)。
  • 解题方向:
    1. 暴力:枚举所有起点,向右扩张直到出现重复,更新答案。
    2. 滑动窗口 + HashSet:维护一个无重复窗口,重复时左指针逐步右移并移除字符。
    3. 滑动窗口 + HashMap(最优):记录每个字符最近一次出现的位置,遇到重复时左指针一次性跳跃到重复字符的下一个位置。
4. 算法详解

解法一:暴力枚举 + 去重检查 {#解法一}

算法原理

  • 基本思想:固定起点 i,使用一个集合记录已出现字符,从 i 向右扩张 j,遇到重复则停止,更新答案。
  • 适用场景:数据量较小、用于直观理解问题结构与边界情况。

具体实现

  • 步骤1:特殊情况处理,若 s 为空或长度为 0,返回 0。
  • 步骤2:外层循环遍历起点 i,内层使用 HashSet 从 i 开始扩张 j,直到遇到重复。
  • 步骤3:过程中维护最长长度 maxLen。

复杂度分析

  • 时间复杂度:O(n^2),最坏情况下(如全不重复),每个起点都可能扫描到末尾。
  • 空间复杂度:O(min(n, Σ)),Σ 为字符集大小,集合中最多存储当前子串的字符数。

Java代码实现

java 复制代码
class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 边界处理:空字符串或null,直接返回0
        if (s == null || s.length() == 0) {
            return 0;
        }
        int n = s.length();
        int maxLen = 0;
        // 外层固定起点 i
        for (int i = 0; i < n; i++) {
            java.util.HashSet<Character> seen = new java.util.HashSet<>();
            // 从 i 向右扩张 j
            for (int j = i; j < n; j++) {
                char c = s.charAt(j);
                if (seen.contains(c)) {
                    // 遇到重复字符,当前起点下的最长子串结束
                    break;
                }
                seen.add(c);
                // 更新答案
                int currLen = j - i + 1;
                if (currLen > maxLen) {
                    maxLen = currLen;
                }
            }
        }
        return maxLen;
    }
}

解法二:滑动窗口(HashMap 下标跳跃) {#解法二}

算法原理

  • 基本思想:使用双指针 left, right 表示当前无重复窗口,HashMap 记录每个字符最近一次出现的下标。
  • 当右指针读到重复字符 c 时,将 left 跳到 max(left, lastIndexc + 1),确保窗口内无重复。
  • 适用场景:通用最优解,线性时间,思路清晰,易于面试手写。

具体实现

  • 步骤1:特殊情况处理,s 为空或长度为 0 返回 0。
  • 步骤2:维护 HashMap<Character, Integer> lastIndex,left 指向当前窗口左边界,遍历 right 从 0 到 n-1。
  • 步骤3:若当前字符 c 在 map 中且上次位置 >= left,则更新 left 为上次位置 + 1;随后更新 map 中 c 的下标为 right,并维护答案。

复杂度分析

  • 时间复杂度:O(n),每个字符至多被左右指针各访问/更新常数次。
  • 空间复杂度:O(min(n, Σ)),Σ 为字符集大小,map 存储窗口中出现过的字符下标。

Java代码实现

java 复制代码
import java.util.HashMap;

class Solution {
    public int lengthOfLongestSubstring(String s) {
        // 边界处理:若字符串为 null 或长度为 0,则没有有效子串,返回 0
        if (s == null || s.length() == 0) {
            return 0;
        }

        // lastIndex 用于记录每个字符最近一次出现的位置(下标)
        HashMap<Character, Integer> lastIndex = new HashMap<>();
        int left = 0;   // 当前无重复窗口的左边界
        int maxLen = 0; // 结果:最长无重复子串长度

        // 使用 right 指针遍历字符串的每个字符
        for (int right = 0; right < s.length(); right++) {
            char c = s.charAt(right);

            // 如果字符 c 出现过,并且它上一次出现位置在当前窗口内
            if (lastIndex.containsKey(c)) {
                int prev = lastIndex.get(c);
                // 将 left 跳到重复字符的下一位,但不能左移(保持单调不回退)
                if (prev + 1 > left) {
                    left = prev + 1;
                }
            }

            // 更新当前字符的最新出现位置
            lastIndex.put(c, right);

            // 计算当前窗口长度并更新答案
            int currLen = right - left + 1;
            if (currLen > maxLen) {
                maxLen = currLen;
            }
        }

        return maxLen;
    }
}
5. 解法对比 {#解法对比}
解法 时间复杂度 空间复杂度 优点 缺点 适用场景
暴力枚举 + 去重检查 O(n^2) O(min(n, Σ)) 思路直观、实现简单 性能较差,无法通过大数据量 入门理解、数据量小
滑动窗口(HashMap 下标跳跃) O(n) O(min(n, Σ)) 线性时间、实现清晰、面试高频 需理解左指针"跳跃"细节 通用最优、面试推荐
6. 最优解推荐 {#最优解推荐}
  • 最优解推荐:滑动窗口(HashMap 下标跳跃)。
  • 原因:在保证 O(n) 时间复杂度的同时,代码可读性强,空间使用可控,适合在面试中快速、稳定地实现与讲解。

三、文章标签

算法,哈希表,滑动窗口,双指针,字符串,LeetCode,中等

四、文章简述

经典字符串题,利用滑动窗口 + 哈希表实现 O(n) 线性解,关键在于用下标映射实现左指针跳跃,避免逐步移动导致退化。适合准备面试与夯实基础的同学,代码注释详尽,便于快速掌握与复盘。

相关推荐
zander25815 分钟前
138. 随机链表的复制
数据结构·算法·链表
过期动态22 分钟前
【LeetCode 热题 100】找到字符串中所有字母异位词
java·数据结构·算法·leetcode·职场和发展·rabbitmq
来一碗刘肉面31 分钟前
栈在递归中的应用
数据结构·算法
8K超高清42 分钟前
博冠获中国电影电视技术学会科技进步奖
人工智能·科技·算法·安全·接口隔离原则·智能硬件
微石科技1 小时前
长期慢病如何做好居家管理?宁波微石科技星梦云康改善周期数据零散短板
大数据·科技·物联网·算法
微露清风1 小时前
快速排序算法学习记录
学习·算法·排序算法
梓䈑7 小时前
【算法题攻略】BFS 解决FloodFill 算法、最短路问题、多源BFS 和 拓扑排序
c++·算法·宽度优先
Adios7949 小时前
设置交集大小至少为2
数据结构·算法·leetcode