news 2026/1/21 20:34:35

双指针专题(七):覆盖所有需求的最小代价——「最小覆盖子串」

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
双指针专题(七):覆盖所有需求的最小代价——「最小覆盖子串」

这道题是Hard级别,也是无数面试者的噩梦。 前面的题(水果成篮、无重复子串)都是窗口**“大了才缩”。 这道题反过来:窗口“不够大(没凑齐)就一直扩,一旦凑齐了就拼命缩”,试图找到最小**的那个解。

力扣 76. 最小覆盖子串

https://leetcode.cn/problems/minimum-window-substring/

题目分析:

  • 输入:字符串s(资源池), 字符串t(需求清单)。

  • 目标:在s中找到一个最短的子串,包含t中所有的字符(包括重复字符,比如t="AA", 子串里也得有两个A)。

  • 输出:这个最短子串。如果不存在,返回空字符串。

例子:s = "ADOBECODEBANC",t = "ABC"

  1. 一直扩:窗口一直向右,直到变成ADOBEC。此时包含了 A, B, C。这是一个可行解,但太长了。

  2. 尝试缩:左边A移出去?不行,A 也是必须的。

  3. 继续跑:...直到找到BANC,包含 A, B, C,且长度只有 4。

核心思维:两个哈希表 + 有效计数器

这道题单纯用 Map 会比较乱,我们需要维护两个概念:

  1. needMap:记录t中每个字符需要多少个。 (比如A:1, B:1, C:1)

  2. windowMap:记录当前窗口里已经有多少个字符。

  3. valid变量:记录有多少个字符已经**“达标”**了。

    • 比如t需要A1个。当窗口里A的数量从 0 变成 1 时,valid++

    • valid等于need.size时,说明所有种类的字符都凑齐了!

操作逻辑:

  1. 进窗口 (right)

    • 读字符,更新windowMap。

    • 如果window[c] === need[c],说明这个字符凑够了,valid++

  2. 收缩窗口 (left)

    • While (valid === need.size):只要凑齐了,就一直缩!

      • 更新结果:如果当前窗口更短,记录下来。

      • 踢出字符:把s[left]移出窗口。

      • 关键判断:如果移出的字符导致window[c] < need[c],说明不再达标了,valid--

      • left++

代码实现 (JavaScript)

JavaScript

/** * @param {string} s * @param {string} t * @return {string} */ var minWindow = function(s, t) { // 1. 统计需求 t const need = new Map(); for (const c of t) { need.set(c, (need.get(c) || 0) + 1); } const window = new Map(); let left = 0, right = 0; let valid = 0; // 记录有多少种字符已经满足要求了 // 记录最小子串的起始位置和长度 let start = 0; let minLen = Infinity; while (right < s.length) { // --- 进窗口 --- const c = s[right]; right++; // 右指针移动 // 如果这个字符是我们需要关注的 if (need.has(c)) { window.set(c, (window.get(c) || 0) + 1); // 如果窗口里的数量刚刚好达到了需求,valid + 1 if (window.get(c) === need.get(c)) { valid++; } } // --- 出窗口 --- // 当 valid 等于 need 的大小时,说明所有字符都凑齐了 // 这时候开始尝试收缩左边界,寻找“最小” while (valid === need.size) { // 更新最小覆盖子串 if (right - left < minLen) { start = left; minLen = right - left; } // 准备移出左边的字符 const d = s[left]; left++; // 如果移出的字符是我们需要关注的 if (need.has(d)) { // 如果移出前,数量刚好达标。那移出后肯定就不达标了 if (window.get(d) === need.get(d)) { valid--; } window.set(d, window.get(d) - 1); } } } return minLen === Infinity ? "" : s.substr(start, minLen); };

深度辨析:为什么是window.get(c) === need.get(c)

  • 假设t = "AA",s = "AAAA"

  • need = {A: 2}

  • right读第一个 A:window={A:1}。不等于 2,valid 不变。

  • right读第二个 A:window={A:2}。等于 2!valid++(A 达标了)。

  • right读第三个 A:window={A:3}。不等于 2,valid 不变。

  • 结论valid只在“刚刚好满足”的那一瞬间增加。这保证了即使窗口里有 100 个 A,valid也只算一次。

总结

拿下这道题,不定长滑动窗口这一块你就彻底毕业了。 它的模板是所有滑动窗口里最全的:

  1. Map 统计需求。

  2. valid变量判断状态。

  3. while(valid === target)进行收缩优化。

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

乡村信息化普及:农民用方言操控智能灌溉系统

乡村信息化普及&#xff1a;农民用方言操控智能灌溉系统 在四川丘陵地带的一处农田边&#xff0c;老张对着田头的语音终端说了句&#xff1a;“把东头那块地浇一下&#xff0c;水别太大。”不到两秒&#xff0c;喇叭里传出一口熟悉的本地口音&#xff1a;“已启动东部灌溉区&am…

作者头像 李华
网站建设 2026/1/2 13:25:21

揭秘FastAPI跨域预检机制:5分钟掌握OPTIONS请求处理核心技巧

第一章&#xff1a;FastAPI跨域预检机制概述在构建现代Web应用时&#xff0c;前端与后端常部署在不同的域名或端口上&#xff0c;导致浏览器出于安全考虑触发同源策略限制。FastAPI作为高性能的Python Web框架&#xff0c;通过集成CORSMiddleware中间件来处理跨域资源共享&…

作者头像 李华
网站建设 2026/1/22 8:04:46

电竞比赛解说生成:AI辅助打造沉浸式观赛体验

电竞比赛解说生成&#xff1a;AI辅助打造沉浸式观赛体验 在一场关键的《英雄联盟》全球总决赛中&#xff0c;Knight的辛德拉精准释放Q技能&#xff0c;瞬间完成双杀。几乎就在击杀发生的同一帧&#xff0c;观众耳机里传来一声激动的播报&#xff1a;“Knight&#xff01;完美施…

作者头像 李华
网站建设 2026/1/2 13:24:01

HuggingFace镜像网站同步更新VoxCPM-1.5-TTS最新版本

HuggingFace镜像网站同步更新VoxCPM-1.5-TTS最新版本 在语音合成技术加速落地的今天&#xff0c;一个能用几秒钟参考音频就“复刻”出某人声音、还能以接近CD级音质输出中文语音的大模型&#xff0c;正悄然降低AI语音应用的门槛。最近&#xff0c;HuggingFace国内镜像站点同步上…

作者头像 李华
网站建设 2026/1/2 13:23:49

自闭症儿童康复训练:温和语音刺激语言能力发展

自闭症儿童康复训练&#xff1a;温和语音刺激语言能力发展 在儿童发育干预领域&#xff0c;语言能力的迟滞始终是自闭症谱系障碍&#xff08;ASD&#xff09;家庭和康复机构面临的核心挑战之一。许多孩子并非“不愿说”&#xff0c;而是缺乏足够稳定、可预测且情感友好的语言输…

作者头像 李华
网站建设 2026/1/11 13:46:39

孕妇胎教音乐伴侣:妈妈每天为宝宝读一首诗

孕妇胎教音乐伴侣&#xff1a;妈妈每天为宝宝读一首诗 在孕期的第28周&#xff0c;胎儿的听觉系统已基本发育成熟。医学研究发现&#xff0c;他们不仅能分辨声音的强弱、节奏快慢&#xff0c;甚至会对母亲的声音产生明显的心率变化反应——这种天然的情感联结&#xff0c;是任何…

作者头像 李华