news 2026/4/18 7:12:44

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

作者头像

张小明

前端开发工程师

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/4/18 3:35:58

为什么顶级公司都在用Uvicorn部署FastAPI?背后的技术逻辑首次公开

第一章&#xff1a;为什么顶级公司都在用Uvicorn部署FastAPI&#xff1f;在构建高性能、可扩展的现代Web API时&#xff0c;FastAPI凭借其类型提示、自动文档生成和出色的性能脱颖而出。然而&#xff0c;真正让FastAPI在生产环境中大放异彩的&#xff0c;是其与Uvicorn的深度集…

作者头像 李华
网站建设 2026/4/17 18:05:10

PyCharm激活码永久免费?不!但VoxCPM-1.5-TTS可合法免费使用

VoxCPM-1.5-TTS&#xff1a;如何用合法、免费的方式实现高质量语音合成&#xff1f; 在智能客服自动播报、有声书批量生成、视障人士辅助阅读等场景中&#xff0c;文本转语音&#xff08;Text-to-Speech, TTS&#xff09;技术正变得无处不在。但你是否也曾为高昂的商用API费用…

作者头像 李华
网站建设 2026/4/18 5:38:15

抑郁症心理疏导:深夜倾诉时有人温柔回应

抑郁症心理疏导&#xff1a;深夜倾诉时有人温柔回应 深夜两点&#xff0c;手机屏幕亮起。一个人蜷在床角&#xff0c;指尖颤抖地敲下&#xff1a;“我好累&#xff0c;没人懂我。” 没有等待客服响应的转接音&#xff0c;也没有冰冷的自动回复。几秒后&#xff0c;一个温和的声…

作者头像 李华
网站建设 2026/4/4 17:42:40

智能硬件集成:VoxCPM-1.5-TTS在IoT设备上的轻量化部署

智能硬件集成&#xff1a;VoxCPM-1.5-TTS在IoT设备上的轻量化部署 在智能家居、儿童教育机器人和无障碍辅助设备日益普及的今天&#xff0c;用户对语音交互体验的要求早已超越“能说话”这一基础功能。人们期待的是自然流畅、富有情感、甚至能模仿亲人声音的个性化语音输出。然…

作者头像 李华