当前位置: 首页 > news >正文

双指针专题(六):贪婪的采摘者——「水果成篮」

场景翻译:

  • 题目说:你有两个篮子,每个篮子只能装一种水果。你从任意一棵树开始往右走,每棵树摘一个,一旦遇到第三种水果,你就不能摘了(因为篮子装不下了),采摘结束。

  • 人话翻译:给定一个数组fruits,请你找到最长的连续子数组,使得这个子数组中至多包含 2 种不同的元素

例子:fruits = [1, 2, 3, 2, 2]

  1. [1, 2]:有 1 和 2 两种。长度 2。

  2. 遇到 3:变成[1, 2, 3](三种了),不行。

    • 必须扔掉前面的 1,窗口变成[2, 3]

  3. 遇到 2:[2, 3, 2](还是 2 和 3 两种),可以!长度 3。

  4. 遇到 2:[2, 3, 2, 2](还是 2 和 3 两种),可以!长度 4

最终答案:4。

力扣 904. 水果成篮

https://leetcode.cn/problems/fruit-into-baskets/

题目分析:

  • 输入:整数数组fruits

  • 目标:找到包含不超过 2 种元素的最长子数组长度。

  • 输出:最大长度。

核心思维:Map 计数器 + 滑动窗口

我们需要一个哈希表 (Map)来充当“篮子”的角色。

  • Key:水果的种类 ID。

  • Value:该种类在当前窗口内的数量

操作逻辑:

  1. 进窗口 (right):把水果加入 Map,计数 +1。

  2. 检查篮子 (Map.size)

    • 如果Map.size > 2,说明窗口里有 3 种水果了,超载了!

    • 出窗口 (left)

      • 开始收缩左边界,把fruits[left]从 Map 里减 1。

      • 关键点:如果减完之后,某个水果的数量变成了0,必须把它从 Map 里delete掉!

      • 只有当Map.size重新回到 2(或更少)时,while循环才能停止。

  3. 更新答案:每次窗口合法时,更新maxLen

代码实现 (JavaScript)

JavaScript

/** * @param {number[]} fruits * @return {number} */ var totalFruit = function(fruits) { let left = 0; let maxLen = 0; // 篮子:记录当前窗口中,每种水果的数量 // key: 水果ID, value: 数量 const basket = new Map(); for (let right = 0; right < fruits.length; right++) { // 1. 进窗口:把右边的水果放进篮子 const rightFruit = fruits[right]; basket.set(rightFruit, (basket.get(rightFruit) || 0) + 1); // 2. 检查:如果篮子里的种类超过 2 种,必须收缩左边界 while (basket.size > 2) { const leftFruit = fruits[left]; // 把左边的水果拿出去 basket.set(leftFruit, basket.get(leftFruit) - 1); // 核心细节:如果这种水果的数量减为 0 了,必须彻底从 Map 中删除 // 否则 Map.size 还是 3,循环不会停,逻辑就错了 if (basket.get(leftFruit) === 0) { basket.delete(leftFruit); } // 左指针前移 left++; } // 3. 此时篮子里一定 <= 2 种,更新最大长度 maxLen = Math.max(maxLen, right - left + 1); } return maxLen; };

深度辨析:为什么必须delete

假设窗口是[1, 2, 3],Map 是{1:1, 2:1, 3:1}(Size=3)。 如果不delete

  • left移出 1。Map 变成{1:0, 2:1, 3:1}

  • Map.size 依然是 3!(因为 key1还在,只是值为 0)。

  • while循环会继续执行,继续移出 2... 直到把篮子空到只剩两种 Key 为止。

  • 这会导致窗口缩得过小,甚至逻辑死循环。

  • 所以,“数量归零 = 彻底移除”是这道题的逻辑核心。

总结

这道题是“至多包含 K 个不同字符的最长子串”问题的标准模板(本题 K=2)。 如果你以后遇到求“至多 K 个”的题目,直接把代码里的basket.size > 2改成basket.size > K即可直接秒杀。


下一题预告:最小覆盖子串

好了,简单的滑动窗口结束了。我们要迎来双指针专题的终极 BOSS——LC 76. 最小覆盖子串(Hard)。

  • 之前的题都是窗口**“太胖了”**(超标了)才收缩。

  • 这道题正好相反:窗口**“太瘦了”(还没凑齐目标字符)就要扩张,一旦“吃饱了”(凑齐了)就要开始拼命收缩**,试图找到一个最短的、能满足要求的窗口。

这就好比:你要去超市买齐清单上的[A, B, C]三样东西。

  • 你一直往前走,直到购物车里凑齐了这三样(可能还有多余的 D, E)。

  • 然后你尝试从购物车底部拿走一些东西,看看能不能在保持 A, B, C 依然齐全的情况下,让付钱的东西最少。

准备好挑战这道 Hard 题了吗?这将是你滑动窗口的毕业考试

http://www.jsqmd.com/news/181831/

相关文章:

  • 幼儿园亲子留言系统:孩子录音转文字再转语音回家播放
  • 学生毕业设计展示:答辩环节加入AI语音辅助讲解
  • 自助售票机交互升级:VoxCPM-1.5-TTS改善用户操作体验
  • 家族族谱语音记录:后代子孙聆听祖先奋斗历程
  • 智能硬件集成:VoxCPM-1.5-TTS在IoT设备上的轻量化部署
  • 智能家居控制反馈:VoxCPM-1.5-TTS提供自然语音回应机制
  • 建筑设计理念阐述:客户戴上耳机感受空间魅力
  • 自闭症儿童康复训练:温和语音刺激语言能力发展
  • 飞机黑匣子语音记录:事故调查新增AI还原功能
  • MySQL远程连接配置与安全实战
  • 视频自动字幕生成器 (Video Subtitle Generator)
  • FastAPI跨域问题深度解析(预检请求避坑宝典)
  • 探索VoxCPM-1.5-TTS的声音克隆能力:个性化语音不再是难题
  • HuggingFace镜像网站同步更新VoxCPM-1.5-TTS最新版本
  • Python大模型显存占用过高?5种实战策略助你降低30%以上显存消耗
  • Python 3.13 废弃特性深度解读:影响你项目的3个关键点
  • 为什么你的Streamlit应用不够“高级”?主题自定义的4个核心秘诀
  • PyCharm激活码永久免费?不!但VoxCPM-1.5-TTS可合法免费使用
  • NiceGUI表单验证实战精讲(99%开发者忽略的关键细节)
  • 医疗语音助手开发:基于VoxCPM-1.5-TTS构建问诊引导系统
  • 在线课程语音讲解:教育平台集成VoxCPM-1.5-TTS提升用户体验
  • 医院叫号系统语音播报:减少人工干预提高运营效率
  • 学校上课铃声个性化:每个班级都有自己的专属铃音
  • 外语学习辅助:VoxCPM-1.5-TTS模拟真人发音帮助口语训练
  • 开发者远程办公环境搭建:数据库与代码同步
  • PyWebIO文件处理实战(从入门到精通):解决90%开发者遇到的上传难题
  • 使用Jupyter Notebook调试VoxCPM-1.5-TTS-WEB-UI输出结果
  • 揭秘NiceGUI输入校验陷阱:5个你必须掌握的防御性编程技巧
  • 【高并发必看】FastAPI限流最佳实践:3个真实线上案例深度剖析
  • 2025空间智能技术大爆发