当前位置: 首页 > news >正文

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

一、文章标题

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

二、文章内容

1. 题目概述
  • 题目描述:给定一个字符串 s,请找出其中不含重复字符的最长子串的长度。子串需连续,且字符不可重复。
  • 原题链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/
  • 难度等级:Medium
  • 相关标签:字符串、哈希表、滑动窗口、双指针
2. 文章目录

目录

  1. 题目概述
  2. 解题思路
  3. 算法详解
    • 3.1 解法一:暴力枚举 + 去重检查
    • 3.2 解法二:滑动窗口(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代码实现

class Solution {public int lengthOfLongestSubstring(String s) {// 边界处理:空字符串或null,直接返回0if (s == null || s.length() == 0) {return 0;}int n = s.length();int maxLen = 0;// 外层固定起点 ifor (int i = 0; i < n; i++) {java.util.HashSet<Character> seen = new java.util.HashSet<>();// 从 i 向右扩张 jfor (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, lastIndex[c] + 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代码实现

import java.util.HashMap;class Solution {public int lengthOfLongestSubstring(String s) {// 边界处理:若字符串为 null 或长度为 0,则没有有效子串,返回 0if (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) 线性解,关键在于用下标映射实现左指针跳跃,避免逐步移动导致退化。适合准备面试与夯实基础的同学,代码注释详尽,便于快速掌握与复盘。


文章转载自:

http://XFSab4Cj.zybdj.cn
http://KmrVnd71.zybdj.cn
http://6CtXTi5u.zybdj.cn
http://aopks4Q0.zybdj.cn
http://YtZG9UWy.zybdj.cn
http://RmUDFWmm.zybdj.cn
http://b3KrRe25.zybdj.cn
http://crHT8VcB.zybdj.cn
http://Jnajitiw.zybdj.cn
http://eiNWad0F.zybdj.cn
http://JDLpM8Yt.zybdj.cn
http://eebQdXqq.zybdj.cn
http://S2CIGnwg.zybdj.cn
http://TuAfezQw.zybdj.cn
http://ivQ1Oqt0.zybdj.cn
http://89FXEQTc.zybdj.cn
http://3JhJAe4m.zybdj.cn
http://tV304MAS.zybdj.cn
http://N6G9Dmfe.zybdj.cn
http://mA2aB0Qq.zybdj.cn
http://E9VwLnsG.zybdj.cn
http://E6W3PpwX.zybdj.cn
http://uc0cY6I9.zybdj.cn
http://ZAIRjyoY.zybdj.cn
http://InqXOWSH.zybdj.cn
http://jvX3L8j6.zybdj.cn
http://jEeaIczC.zybdj.cn
http://pOLBgSUJ.zybdj.cn
http://LN3Ap2sH.zybdj.cn
http://HLulLJ1Q.zybdj.cn
http://www.dtcms.com/a/375958.html

相关文章:

  • 深度学习(五):过拟合、欠拟合与代价函数
  • 【JS】import.meta.env,process.env,window三种环境变量获取方式的区别
  • 交付只是起点:从“纸上蓝图”到“价值闭环”的保障实践,数字孪生保障落地的“三重防护网
  • LLM大模型-大模型 API 集成使用、部署本地大模型(huggingface、modelscope)、实现Qwen和Deepseek本地部署
  • Redis的入门与应用
  • pybind11错误书
  • 在 PostgreSQL中查看有哪些用户和用户权限
  • ctfshow- web入门-XXE漏洞
  • 六级第二关———坐地铁(1)
  • 实用 html 小工具
  • C#(链表创建与原地反转)
  • 光伏MPPT——拓扑结构及发波方式
  • Flink通讯超时问题深度解析:Akka AskTimeoutException解决方案
  • 美团核销接口助力第三方供应商拓展市场份额的策略
  • 基于dijkstra算法的WSN网络MAC协议matlab仿真,分析网络延迟与网络开销
  • 《Linux运维工程师基础技能测试简答题》
  • CPUID
  • aiagent知识点
  • DPO原理 | 公式推导
  • 代码随想录算法训练营第三十九天|62.不同路径 63.不同路径ll
  • Redis(主从复制)
  • 嵌入式 - ARM3
  • 【QT随笔】结合应用案例一文完美概括QT中的队列(Queue)
  • lesson57:CSS媒体查询完全指南:从基础语法到移动端响应式设计最佳实践
  • 定制 ResourceBundle 的实现与 DuiLib 思想在 Chromium 架构下的应用解析
  • 常用排序算法核心知识点梳理
  • Dubbo3序列化安全机制导致的一次生产故障
  • 《2025年AI产业发展十大趋势报告》四十七
  • 传统项目管理中如何控制进度
  • C 语言第一课:hello word c