LeetCode Hot100(7/100)—— 3. 无重复字符的最长子串

文章目录

一、题目描述

给定一个字符串 s ,请你找出其中 不含重复字符最长子串 的长度。

示例:

复制代码
输入: s = "abcabcbb"
输出: 3
解释: 最长子串是 "abc",长度为 3。

二、问题分析

这道题要求找出 最长的无重复字符的连续子串

可以想到用 暴力枚举法滑动窗口法

  • 暴力:枚举所有子串 → 检查是否重复 → 找最长长度。
  • 滑动窗口:用双指针维护一段不重复的区间 → 动态右扩,必要时左缩。

显然,滑动窗口是最优解法,因为它避免了重复检查。


三、解法一:暴力枚举法

思路

  • 枚举所有可能的子串起点和终点。
  • 判断该子串中是否有重复字符。
  • 记录最长长度。

流程图(暴力枚举)

无重复
有重复
开始
初始化 maxLen = 0
遍历左指针 i from 0..n-1
遍历右指针 j from i..n-1
获取 s[i..j]
判断是否有重复字符
更新 maxLen
继续遍历
结束
返回 maxLen

时间复杂度分析

  • 时间复杂度: O(n³) (枚举所有子串 + 检查重复)
  • 空间复杂度: O(n)

不适合大数据量。


四、解法二:滑动窗口(推荐)

思路说明

滑动窗口法通过维护一段 无重复的子串区域 来动态更新结果:

  • 使用两个指针 leftright 表示窗口边界。
  • 使用一个 HashSetHashMap 记录窗口中字符出现位置。
  • 每次右指针向右移动:
    • 若新字符不存在于窗口,则加入并更新长度。
    • 若新字符已出现,则左指针右移到出现位置之后。

动态示意图

假设输入 s = "abcabcbb"

步骤 右指针字符 当前窗口 最大长度
1 a a 1
2 b ab 2
3 c abc 3
4 a bca 3
5 b cab 3
6 c abc 3

最终结果为 3

流程图(滑动窗口)

渲染错误: Mermaid 渲染失败: Parse error on line 5: ...|重复| E[更新 left = max(left, map[char] + 1 -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'


五、复杂度分析

项目 时间复杂度 空间复杂度
暴力枚举 O(n³) O(n)
滑动窗口 O(n) O(k),其中 k 为字符集大小

滑动窗口显然更优。


六、Java 实现代码(滑动窗口)

java 复制代码
class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int left = 0, maxLen = 0;
        Map<Character, Integer> map = new HashMap<>();

        for (int right = 0; right < n; right++) {
            char c = s.charAt(right);
            if (map.containsKey(c)) {
                // 更新左指针到重复字符之后位置
                left = Math.max(left, map.get(c) + 1);
            }
            map.put(c, right);
            maxLen = Math.max(maxLen, right - left + 1);
        }
        return maxLen;
    }
}

七、补充:使用数组优化

若字符集已知(如仅英文字符),可用数组代替 Map:

java 复制代码
class Solution {
    public int lengthOfLongestSubstring(String s) {
        int[] index = new int[128]; // ASCII
        int left = 0, maxLen = 0;
        for (int right = 0; right < s.length(); right++) {
            char c = s.charAt(right);
            left = Math.max(index[c], left);
            maxLen = Math.max(maxLen, right - left + 1);
            index[c] = right + 1;
        }
        return maxLen;
    }
}

总结

方法 核心思路 时间复杂度 是否推荐
暴力法 枚举所有子串 + 检查重复 O(n³)
滑动窗口 + HashMap 动态维护无重复窗口 O(n) ✅ 推荐
滑动窗口 + 数组优化 改进存储结构 O(n) ✅ 推荐
相关推荐
We་ct2 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·javascript·算法·leetcode·typescript
王老师青少年编程6 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮6 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
天疆说6 小时前
【哈密顿力学】深入解读航天器交会最优控制中的Hamilton函数
人工智能·算法·机器学习
wuweijianlove7 小时前
关于算法设计中的代价函数优化与约束求解的技术7
算法
leoufung8 小时前
LeetCode 149: Max Points on a Line - 解题思路详解
算法·leetcode·职场和发展
样例过了就是过了8 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
HXDGCL8 小时前
矩形环形导轨:自动化循环线的核心运动单元解析
运维·算法·自动化
谭欣辰8 小时前
C++ 排列组合完整指南
开发语言·c++·算法
代码中介商8 小时前
银行管理系统的业务血肉 —— 流程、状态机、输入校验与持久化(下篇)
c语言·算法