力扣解题-无重复字符的最长子串

力扣解题-无重复字符的最长子串

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

示例 1:

输入: s = "abcabcbb"

输出: 3

解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。注意 "bca" 和 "cab" 也是正确答案。

示例 2:

输入: s = "bbbbb"

输出: 1

解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

示例 3:

输入: s = "pwwkew"

输出: 3

解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。

请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

提示:

0 <= s.length <= 5 * 104

s 由英文字母、数字、符号和空格组成


第一次解答

解题思路

核心方法:滑动窗口(双指针) + 哈希集合去重,通过动态调整窗口的左右边界,在一次遍历中找到无重复字符的最长子串,将暴力解法的O(n²)时间复杂度优化至O(n),是该问题的经典最优解法。

具体步骤:

  1. 核心原理铺垫 :滑动窗口是解决"子串/子数组"类问题的常用技巧,本题中用leftright两个指针分别表示窗口的左、右边界,窗口[left, right]内始终维护一个"无重复字符的子串",通过动态调整边界来找到最长窗口长度。
  2. 初始化关键变量
    • seenHashSet<Character>集合,用于快速判断当前字符是否已在窗口内(O(1)查找效率),存储当前窗口内的所有字符;
    • left:窗口左指针,初始值为0,代表窗口起始位置;
    • maxLength:记录遍历过程中找到的最长无重复子串长度,初始值为0。
  3. 右指针遍历扩展窗口
    • 右指针right从0开始遍历字符串的每个字符c = s.charAt(right),代表尝试将当前字符加入窗口;
    • 若当前字符c已存在于seen集合中(说明窗口内有重复字符),则进入循环收缩左边界:
      • 移除左指针left指向的字符(seen.remove(s.charAt(left)));
      • 左指针left右移一位(left++);
      • 重复上述操作,直到seen中不再包含c(此时窗口内恢复无重复状态)。
    • 将当前字符c加入seen集合(此时c是窗口新的右边界字符);
    • 计算当前窗口的长度(right - left + 1),并更新maxLength为"当前最大值"和"窗口长度"中的较大者。
  4. 返回结果 :遍历完成后,maxLength即为无重复字符的最长子串长度,直接返回。

核心优化逻辑说明

  1. 时间复杂度优化
    • 暴力解法需枚举所有子串(O(n²)),并对每个子串检查是否有重复(O(n)),总时间复杂度O(n³),无法适配n=5×10⁴的规模;
    • 滑动窗口仅需一次遍历(右指针遍历n次),左指针最多也移动n次,整体时间复杂度为O(n)(每个字符最多被左/右指针各访问一次),完全满足题目性能要求。
  2. 空间复杂度说明
    • 该解法用HashSet存储窗口内字符,最坏情况下(字符串无重复)需存储n个字符,空间复杂度为O(n),这是"时间换空间"的合理权衡;
    • 若需进一步优化空间,可改用数组(ASCII字符范围)替代HashSet,但核心逻辑不变,仅存储方式不同。
  3. 性能表现说明:
    • 耗时5ms击败32.91%的用户:滑动窗口是该题的标准最优解,多数提交均采用此逻辑,耗时差异主要来自评测机运行环境(如JVM的即时编译、系统资源占用等),该耗时已属于高效范畴;
    • 内存消耗76MB击败19.06%的用户:核心原因是HashSet的底层存储(如HashMap的数组+链表/红黑树结构)存在额外内存开销,若改用数组存储字符是否存在,可降低内存消耗。

执行耗时:6 ms,击败了61.68% 的Java用户

内存消耗:45.9 MB,击败了13.31% 的Java用户

java 复制代码
public int lengthOfLongestSubstring(String s) {
        Set<Character> seen = new HashSet<>();
        int left = 0, maxLength = 0;

        for (int right = 0; right < s.length(); right++) {
            char c = s.charAt(right);
            while (seen.contains(c)) {
                seen.remove(s.charAt(left));
                left++;
            }
            seen.add(c);
            maxLength = Math.max(maxLength, right - left + 1);
        }
        return maxLength;
    }

总结

  1. 该解法的核心是滑动窗口动态维护无重复子串:右指针扩展窗口,左指针收缩窗口以消除重复,确保窗口内始终无重复字符,一次遍历即可找到最长长度;
  2. HashSet的O(1)查找效率是滑动窗口能高效运行的关键,避免了每次检查重复都遍历窗口的冗余操作;
  3. 滑动窗口的时间复杂度O(n)是该问题的最优下界,无法进一步优化,该解法已达到理论最优性能。
相关推荐
故事和你9120 小时前
sdut-程序设计基础Ⅰ-实验五一维数组(8-13)
开发语言·数据结构·c++·算法·蓝桥杯·图论·类和对象
像污秽一样20 小时前
算法与设计与分析-习题4.2
算法·排序算法·深度优先·dfs·bfs
无限大620 小时前
《AI观,观AI》:善用AI赋能|让AI成为你深耕核心、推进重心的“最强助手”
前端·后端
uzong20 小时前
CoPaw是什么?-- 2026年开源的国产个人AI助手
人工智能·后端
无心水21 小时前
【任务调度:框架】11、分布式任务调度进阶:高可用、幂等性、性能优化三板斧
人工智能·分布式·后端·性能优化·架构·2025博客之星·分布式调度框架
pjw1988090321 小时前
Spring Framework 中文官方文档
java·后端·spring
Storynone21 小时前
【Day20】LeetCode:39. 组合总和,40. 组合总和II,131. 分割回文串
python·算法·leetcode
盒马盒马21 小时前
Rust:迭代器
开发语言·后端·rust
明明如月学长21 小时前
AI 更新太快学不过来?我用OpenClaw打造专属AI学习工作流
算法
黎阳之光1 天前
【黎阳之光:以无线专网与视频孪生,赋能智慧广电与数字中国】
算法·安全·智慧城市·数字孪生