news 2026/10/15 14:32:35

双指针专题(五):灵活的起跳——「无重复字符的最长子串」

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
双指针专题(五):灵活的起跳——「无重复字符的最长子串」

场景想象:你在排队处理一串项链上的珠子(字符串),你的任务是截取一段颜色都不重复的珠子。

  • 右指针 (right):负责探索,一颗颗把珠子纳入口袋。

  • 左指针 (left):负责“止损”。

    • 一旦右指针发现:“哎呀,这颗红珠子('a')我口袋里已经有一颗了!”

    • 这时候,左指针不需要一步步往右挪,它可以直接跳到口袋里那颗旧红珠子的后面一位。因为旧红珠子前面的所有区间,只要包含旧红珠子,就一定会有重复,所以统统不要了!

力扣 3. 无重复字符的最长子串

https://leetcode.cn/problems/longest-substring-without-repeating-characters/

题目分析:

  • 输入:字符串s。

  • 目标:找到其中不含有重复字符的最长子串的长度。

  • 输出:长度数值。

例子:s = "abcabcbb"

  1. [abc]: 无重复,长3。

  2. 遇到第二个a:重复了!

    • 左指针如果不跳,还在第一个a那里,那就是abca(重复)。

    • 左指针必须跳过第一个a,来到b的位置。当前窗口变[bca]。

  3. 遇到第二个b:

    • 左指针跳过旧的b,来到c的位置。当前窗口变[cab]。

  4. ...

核心思维:Map 记录索引 + 懒加载跳跃

我们需要一个哈希表 (Map)来记录:“某个字符上一次出现在什么位置(下标)”。

关键逻辑:当right遇到一个字符c,且c在 Map 里存在时:

  • 说明遇到重复了。

  • 我们需要把left更新到Map.get(c) + 1的位置(也就是重复字符的下一位)。

  • 但是!有个惊天大坑:

    • 比如abba。

    • 遇到第二个b时,left跳到了2(第二个b的位置)。

    • 接着遇到第二个a。Map 里记着第一个a在0。

    • 如果你直接left = map.get('a') + 1,left会跳回1。

    • 这就倒车了!left只能往右走,不能往回退。

    • 所以正确的逻辑是:left = Math.max(left, map.get(c) + 1)。

代码实现 (JavaScript)

JavaScript

/** * @param {string} s * @return {number} */ var lengthOfLongestSubstring = function(s) { // 记录字符上一次出现的位置 // key: 字符, value: 索引 index let map = new Map(); let left = 0; let maxLen = 0; for (let right = 0; right < s.length; right++) { const c = s[right]; // 1. 如果 map 里有这个字符,说明可能是重复项 if (map.has(c)) { // 2. 更新左边界 // 核心:只能向右跳,不能倒车! // 比如 "abba",遇到第二个 a 时,map.get('a') 是 0,但 left 已经在 2 了 // 所以必须取 max left = Math.max(left, map.get(c) + 1); } // 3. 更新/记录当前字符的最新位置 map.set(c, right); // 4. 更新最大长度 // 当前窗口长度 = right - left + 1 maxLen = Math.max(maxLen, right - left + 1); } return maxLen; };

深度模拟:"abba"

  1. right=0('a'): map无。map={a:0}。max=1。

  2. right=1('b'): map无。map={a:0, b:1}。max=2。

  3. right=2('b'):重复!

    • map有 'b' (index 1)。

    • left = max(0, 1 + 1) = 2。左指针跳到 index 2。

    • 此时窗口是b(index 2)。

    • 更新map={a:0, b:2}。

    • len = 2 - 2 + 1 = 1。max还是 2。

  4. right=3('a'):重复!

    • map有 'a' (index 0)。

    • left = max(2, 0 + 1)。

    • 注意!如果不取 max,left会退回到 1。但我们取 max,所以left保持在 2。

    • 逻辑含义:虽然a重复了,但那个旧的a早就被之前的b重复事件给排除在窗口左边了,所以不用管它。

    • 更新map={a:3, b:2}。

    • len = 3 - 2 + 1 = 2。

总结

这道题的精髓在于:滑动窗口 + 哈希索引优化。 普通滑动窗口是left++一步步挪,而这道题利用 Map 实现了left的精准空降。

记住那个坑:left = Math.max(left, map.get(c) + 1)。这是防止“时光倒流”的护身符。


下一题预告:水果成篮

做完了“无重复的最长子串”,下一题LC 904. 水果成篮(Medium) 就是它的孪生兄弟。

  • 题目:你有两个篮子,每个篮子只能装一种类型的水果。

  • 目标:找到最长的连续子序列,使得其中至多包含两种不同的元素。

    • 比如[1, 2, 1, 2, 3]-> 最长是[1, 2, 1, 2],长度 4。一旦遇到 3,就变成三种了,必须扔掉前面的。

  • 这道题其实就是:“至多包含 K 个不同字符的最长子串”(这里 K=2)。

准备好去果园摘水果了吗?逻辑和这道题非常像,但 Map 的用法略有不同哦!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 18:22:40

脱口秀段子语音表达:喜剧演员灵感激发新工具

脱口秀段子语音表达&#xff1a;喜剧演员灵感激发新工具 在脱口秀创作的幕后&#xff0c;有一个鲜为人知却至关重要的环节——“试讲”。一个段子写完后&#xff0c;演员往往需要反复念出来&#xff0c;测试节奏、调整停顿、捕捉笑点爆发的最佳时机。但问题是&#xff0c;人脑在…

作者头像 李华
网站建设 2026/10/14 21:37:22

网约车司机服务问候语:品牌化语音提升乘客好感度

网约车司机服务问候语&#xff1a;品牌化语音提升乘客好感度 在早晚高峰的街头&#xff0c;一辆网约车缓缓停靠&#xff0c;乘客打开车门的一瞬间&#xff0c;车内传来一句温和而清晰的声音&#xff1a;“您好张先生&#xff0c;我是李师傅&#xff0c;今天全程为您服务&#x…

作者头像 李华
网站建设 2026/10/15 1:54:27

在线测评系统反馈:考试结束后立即听取成绩分析

在线测评系统反馈&#xff1a;考试结束后立即听取成绩分析 在一场线上数学测验结束的瞬间&#xff0c;学生点击“提交试卷”后&#xff0c;耳边立刻响起温和而熟悉的教师声音&#xff1a;“你本次得分87分&#xff0c;函数部分掌握得不错&#xff0c;但几何题失分较多&#xf…

作者头像 李华
网站建设 2026/10/15 6:47:59

揭秘NiceGUI输入校验陷阱:5个你必须掌握的防御性编程技巧

第一章&#xff1a;揭秘NiceGUI输入校验的核心机制NiceGUI 是一个基于 Python 的轻量级 Web 框架&#xff0c;专为快速构建交互式用户界面而设计。其输入校验机制依托于组件级别的事件驱动模型&#xff0c;能够在用户交互过程中实时验证数据合法性&#xff0c;从而提升用户体验…

作者头像 李华
网站建设 2026/10/15 20:44:36

健身房课程预告:会员到店即收今日精彩活动

高品质语音合成的平民化之路&#xff1a;从模型到网页的一键部署实践 在健身房门口&#xff0c;你是否曾听到过机械感十足的广播&#xff1a;“尊敬的会员&#xff0c;今天的课程即将开始。” 这类通知虽然实用&#xff0c;但冰冷的声音总让人觉得少了点温度。如果系统能用接近…

作者头像 李华
网站建设 2026/10/15 20:41:24

岁末年初,测试人的雷达在扫什么?

午后的办公室&#xff0c;敲击键盘的声音稀疏了些。窗外或许已有零星的节日装饰&#xff0c;而你的屏幕上&#xff0c;可能正运行着本年最后一轮回归测试&#xff0c;或者盯着来年的测试计划草案出神。我们的“职业雷达”会从日常高强度的用例执行、缺陷跟踪中暂时抽离&#xf…

作者头像 李华