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

文章目录

一、题目描述

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

示例:

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

二、问题分析

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

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

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

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


三、解法一:暴力枚举法

思路

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

流程图(暴力枚举)

无重复
有重复
开始
初始化 maxLen = 0
遍历左指针 i from 0..n-1
遍历右指针 j from i..n-1
获取 si..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) ✅ 推荐
相关推荐
土司大王1 小时前
LeetCode hot100——两两交换链表中的节点
算法·leetcode·职场和发展
大熊背2 小时前
树莓派IspPipeline LSC模块原理详解
算法·lsc·isppipeline·mesh lsc
zander2583 小时前
LeetCode 300. 最长递增子序列
算法·leetcode·深度优先
欧叶冲冲冲3 小时前
Python常见数据结构的CRUD(LeetCode高频版速查)
数据结构·python·leetcode
祖力554 小时前
Linux应用软件编程:目录IO与framebuffer
linux·运维·算法·framebuffer·目录io
名字还没想好☜4 小时前
Go 用 slices/maps 标准库泛型函数:告别手写 Contains、Sort、去重(Go 1.21)
开发语言·后端·算法·golang·go
地平线开发者4 小时前
【模型轻量化专题】深度学习模型为什么需要轻量化
算法
圣保罗的大教堂4 小时前
leetcode 3622. 判断整除性 简单
leetcode
_Narcissus_4 小时前
链表算法题和静态链表
数据结构·c++·笔记·算法·链表·ai·力扣
Lyyaoo.4 小时前
【普通数组】【中等】除了自身以外数组的乘积
数据结构·算法·leetcode