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) ✅ 推荐
相关推荐
jiang_changsheng2 小时前
comfyui节点插件笔记总结新增加
人工智能·算法·计算机视觉·comfyui
重生之我是Java开发战士2 小时前
【优选算法】双指针法:移动0,复写0,快乐数,盛水最多的容器,有效三角形个数,二三四数之和
算法
客卿1232 小时前
力扣二叉树简单题整理--(包含常用语法的讲解)
算法·leetcode·职场和发展
hrrrrb2 小时前
【算法设计与分析】递归与分治策略
算法
We་ct2 小时前
LeetCode 28. 找出字符串中第一个匹配项的下标:两种实现与深度解析
前端·算法·leetcode·typescript
血小板要健康3 小时前
118. 杨辉三角,力扣
算法·leetcode·职场和发展
_OP_CHEN3 小时前
【算法基础篇】(五十一)组合数学入门:核心概念 + 4 种求组合数方法,带你快速熟悉组合问题!
c++·算法·蓝桥杯·排列组合·组合数学·组合数·acm/icpc
漫随流水3 小时前
leetcode回溯算法(491.非递减子序列)
数据结构·算法·leetcode·回溯算法
睡一觉就好了。3 小时前
排序--直接排序,希尔排序
数据结构·算法·排序算法