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

LeetCode 209:长度最小的子数组(滑动窗口) —— 题解

👋 欢迎阅读

一.题目

209. 长度最小的子数组 - 力扣(LeetCode)

🎯 欢迎来到「长度最小的子数组」题解之旅!本文将带你从“寻找和大于等于目标值的最短连续子数组”这一优化问题出发,深入理解滑动窗口(双指针)的经典应用,并掌握如何通过动态调整窗口边界在 O(n)O(n) 时间内找到最优解。

在开始之前,建议你先:

  • 了解题目背景:这是 LeetCode 209 题,给定一个由正整数组成的数组nums和目标值target,要求找到和 ≥ target 的最短连续子数组,并返回其长度;若不存在则返回0。由于数组中全是正数,窗口和具有单调性——右指针扩展时和增大,左指针收缩时和减小,这为滑动窗口提供了天然的条件。

  • 明确学习目标:掌握滑动窗口核心流程——右指针right不断向右扩展,累加元素和;一旦窗口内和>= target,就尝试收缩左指针left(将左侧元素移出窗口),在收缩过程中持续更新满足条件的最小窗口长度,直到和再次小于target,然后继续扩展右指针。理解为什么“右扩左缩”的策略能遍历所有可能的窗口并保证不漏解,并熟练处理边界情况(如无解返回0)。

  • 准备好环境:建议在本地 IDE 或 LeetCode 在线编辑器中打开代码,边看边运行,亲手验证示例(如target = 7, nums = [2,3,1,2,4,3]输出2)。

本文将从问题转化、滑动窗口策略设计(右扩左缩)、窗口收缩条件到代码实现,层层递进。即使你对滑动窗口还不熟悉,我们也会从“先扩展右边凑够目标,再收缩左边找最短”这一直觉出发,让你轻松抓住核心思想——利用正数数组的和单调性,用双指针维护一个动态窗口,在满足条件时不断压缩窗口,从而找到全局最短。现在,让我们一起在数组中滑动窗口,找出那个和达标的最短子数组吧! 📏🔢

二.做题思路

一、问题分析(前置分析)

给定一个正整数数组nums和一个正整数target,要求找到和 ≥ target 的最短连续子数组,返回其长度。若不存在,返回 0。
核心观察:所有数均为正,因此窗口内和随右指针扩大而单调递增,随左指针收缩而单调递减。这正好适合滑动窗口(双指针),可以在 O(n) 时间内解决。


二、算法策略(滑动窗口)

  • 使用左右指针leftright维护一个窗口,初始left = 0right = 0

  • 右指针right从 0 到 n-1 依次遍历,将nums[right]加入窗口和sum

  • 每加入一个元素后,检查当前窗口和是否 ≥ target

    • 若是,则尝试收缩左指针left++)来缩小窗口,同时更新最小长度len = min(len, right-left+1)

    • 重复收缩直到窗口和 < target。

  • 遍历结束后,若len仍为INT_MAX,返回 0;否则返回len

示例执行过程target = 7, nums = [2, 3, 1, 2, 4, 3]):

步骤right操作窗口[left, right]窗口和是否 ≥7操作后len
初始---0-
10加入2[0,0]2
21加入3[0,1]5
32加入1[0,2]6
43加入2[0,3]8收缩:左移0→1,和6,更新 len=4;继续收缩:左移1→2,和3<7 停止
54加入4[2,4]7收缩:左移2→3,和6<7 停止,更新 len=3
65加入3[3,5]9收缩:左移3→4,和7≥7,更新 len=2;再收缩:左移4→5,和3<7 停止

最终len = 2,对应子数组[4, 3],返回 2。


三、正确性说明(简单版本)

滑动窗口利用所有数为正的性质,保证了窗口和是右指针的单调增函数。当窗口和 ≥ target 时,当前窗口是满足条件且以right为右端点的最短窗口(因为一旦和满足,我们就不断收缩左指针,直到刚好不满足,此时窗口长度就是该右端点下的最短长度)。由于我们遍历所有可能的右端点,并记录每个右端点下的最短长度,取全局最小值,因此不会遗漏任何候选子数组。该算法正确性由滑动窗口的单调性和遍历完整性保证。


四、实现细节(边界防护)

  • 初始化left = 0sum = 0len = INT_MAX

  • for (int right = 0; right < n; ++right)遍历:

    • sum += nums[right]

    • while (sum >= target)循环收缩:

      • len = min(len, right - left + 1)

      • sum -= nums[left++]

  • 循环结束后,若len == INT_MAX,返回 0;否则返回len

  • 时间复杂度 O(n)(每个元素最多入窗一次、出窗一次),空间复杂度 O(1)。


五、返回值(目标映射)

返回len,即满足条件的最短连续子数组长度。若不存在,返回 0。

三.代码

#include <iostream> #include <vector> #include <climits> using namespace std; class Solution { public: int minSubArrayLen(int target, vector<int>& nums) { // 算法思路:滑动窗口(双指针) // 右指针不断向右扩展窗口,累加元素和; // 一旦窗口内和 >= target,就尝试收缩左指针(缩小窗口), // 并在此过程中更新满足条件的最小窗口长度。 // 直到右指针到达数组末尾,返回最小长度;若不存在则返回0。 int n = nums.size(); int sum = 0; // 当前窗口内元素的和 int len = INT_MAX; // 记录满足条件的最小窗口长度,初始化为最大值 // 使用 for 循环,右指针 right 从 0 到 n-1 遍历数组 for (int left = 0, right = 0; right < n; right++) { // 入窗口:将 nums[right] 加入当前窗口的和 sum += nums[right]; // 当窗口内和 >= target 时,尝试收缩窗口,寻找更短的满足条件的子数组 while (sum >= target) { // 更新最小长度:当前窗口长度为 right - left + 1 len = min(len, right - left + 1); // 出窗口:将 nums[left] 从和中移除,左指针右移 sum -= nums[left]; left++; } } // 如果 len 仍为 INT_MAX,说明不存在这样的子数组,返回0 if (len == INT_MAX) { return 0; } // 否则返回最小长度 return len; } }; int main() { // 测试用例:target = 7, nums = [2,3,1,2,4,3],期望输出 2 int target = 7; vector<int> nums = {2, 3, 1, 2, 4, 3}; Solution sol; int result = sol.minSubArrayLen(target, nums); cout << result << endl; // 输出 2 return 0; }

四、易错点分析

4.1 收缩窗口时使用while而非if

while (sum >= target) { len = min(len, right - left + 1); sum -= nums[left]; left++; }

易错原因:
当窗口和满足条件时,需要持续收缩左指针直到窗口和小于target,因为要找到以当前right结尾的最短子数组。若误写成if只收缩一次,则只能得到一个满足条件的窗口,但可能不是最短的(例如窗口内元素全为正数,收缩一次后和仍 ≥ target,此时更短的窗口未被记录)。必须用while不断尝试收缩,确保每个右边界下都找到最小长度。


4.2 更新len的位置:应在收缩窗口循环内部

while (sum >= target) { len = min(len, right - left + 1); sum -= nums[left]; left++; }

易错原因:
len必须在每次收缩时更新,因为每收缩一次都可能产生更短的满足条件的子数组。若将len更新写在while循环外面(如紧跟在for循环内、while之后),则只会记录第一次满足时的长度,后续收缩得到的更短长度会被遗漏。正确做法是将len更新放在while循环体的第一行,确保每次左指针移动前都记录当前窗口长度。


4.3 左指针自增时,sum的减操作顺序

sum -= nums[left]; left++;

易错原因:
出窗口时必须先用nums[left]减去当前值,再left++若顺序写反(先left++sum -= nums[left],则减去的是下一个元素的值,导致窗口和计算错误。虽然本题中left++后减的是新位置的元素,看似sum变化但逻辑完全错误,会漏掉原本left位置的元素,使窗口和偏小,最终可能漏解或得到错误的最小长度。务必记住:先减后移

五、流程图

🎯 闭幕

🎉 恭喜你完成了「长度最小的子数组」问题的学习!

为了巩固知识并进一步拓展,建议你:

🚀动手实践
在 LeetCode 上提交代码,尝试不同的测试用例。

💡深入思考

  • 本题使用滑动窗口,右指针不断扩展,当窗口和 >= target 时,尝试收缩左指针。请问为什么窗口和满足条件后要收缩左指针?收缩的目的是什么?

  • 如果数组元素全是正数,滑动窗口可以保证单调性(窗口和随右移增大,随左移减小)。如果数组中存在负数,当前算法是否仍然正确?为什么?

  • 代码中len初始化为INT_MAX,最后判断是否变化。如果target很小,整个数组和都小于 target,此时len保持INT_MAX,返回 0,这个处理是否正确

  • 滑动窗口的时间复杂度为O(n),而题目进阶要求 O(n log n) 解法(如前缀和 + 二分)。请思考:在什么情况下 O(n) 比 O(n log n) 更优?为什么本题仍给出进阶要求?

  • 如果数组长度为10^5,每个元素最大10^4,窗口和最大为10^9sum使用int是否会溢出?需要改用long long吗?

📚延伸挑战

  • 如果题目要求返回满足和 >= target 的子数组的起始和结束下标(而不是长度),代码应做哪些调整?

  • 如果要求找到和恰好等于 target 的最短子数组(而非大于等于),滑动窗口应如何修改?

如果你觉得本文对你有所帮助,欢迎:

👍点赞 / 收藏
👤关注作者,获取更多题解
💬留言交流你的疑问或优化思路


📌深入思考答案

  • 收缩左指针是因为当前窗口已经满足条件,为了找到更短的子数组,需要尝试去掉左侧元素,在保持和 >= target 的前提下缩短窗口长度,这是滑动窗口寻找最小窗口的核心操作。

  • 若存在负数,窗口和不再单调(加入负数可能使和减小),此时滑动窗口的收缩条件失效(和减少后可能再次满足条件,需要重新扩展),算法会出错,因此本题明确限定数组为正整数

  • 返回 0 是正确的,因为INT_MAX表示未找到任何满足条件的子数组,题意明确要求不存在时返回 0。

  • O(n) 在时间上优于 O(n log n),但进阶要求可能是为了考查多种解法的掌握(如前缀和+二分),实际应用中 O(n) 已最优,进阶属于拓展思维。

  • nums[i]最大10^4n最大10^5,窗口和最大10^9仍在 32 位 int 范围内(约 21 亿),因此int足够安全,无需long long

🔍延伸挑战答案

  • 挑战1:只需在更新len时同时记录leftright作为起始和结束下标,最后返回该对下标即可,其他逻辑不变。

  • 挑战2:若要求和恰好等于target,当窗口和大于 target 时不能直接收缩,因为和可能因后续加入负数而变小(但本题全为正数,因此一旦和大于 target,收缩左指针无法再回到恰好值),需要改用前缀和 + 哈希双指针配合额外判断,滑动窗口不再适用。

祝你在算法之路上越走越稳,早日攻克每一道难题!下次见 🚀✨

http://www.cnnetsun.cn/news/3988234.html

相关文章:

  • 济南网站建设 刘彬彬:在泉水边死磕每一行代码的十年,聊聊为什么你的网站总是留不住客户
  • 3分钟上手biliTickerBuy:零基础抢到B站热门漫展票的终极指南
  • 制作精美网站建设服务周到-让每一次点击都成为品牌价值的延伸
  • Hindsight消息传递机制:确保至少一次交付的核心设计
  • AWS Security Agent 实战:AI 驱动的应用安全评估从零落地(渗透测试+代码审计+威胁建模)
  • 深度解析lspci:从PCIe拓扑到硬件性能调优的实战指南
  • 如何用3行代码集成验证码破解API?gh_mirrors/ca/captcha_crack服务器部署教程
  • Linux服务器CPU占用过高排查与优化实战指南
  • AR-1106定位支路旁路降噪的相位一致性分析
  • Ketch核心组件解析:深入理解应用部署的幕后英雄
  • 深入解析Xilinx MIG IP核APP接口:FPGA与DDR3握手机制与设计实践
  • 揭秘企业官网成功基石:深度解析网站建设需求调研方法的核心逻辑与实践指南
  • 标准化建设考评网站如何助力企业合规管理?揭秘高效转型的秘密武器
  • 终极指南:如何让Emby/Jellyfin完美调用本地播放器实现无缝播放体验
  • AI智能体公司:TeleAgent放进桌面办公赛道前列
  • 从理论到实战:深入剖析创建型设计模式及其工程落地
  • CentOS/Linux下Docker部署MySQL 5.7全攻略:从离线安装到生产级配置
  • Navicat Premium 17(2026)安装教程
  • LeetCode 39:组合总和——Java DFS 回溯与剪枝详解
  • 揭秘东港区建设局官网背后的民生温度与城市进化史——探访东港区建设局网站最新动态与服务升级
  • 达州网站建设qinsanw如何助力中小企业实现数字化转型的实战经验分享
  • 深入理解C语言中的static与函数传参
  • 指针运算与内存访问详解
  • Vue可拖拽组织树组件实战:从zm-org-tree选型到性能优化全解析
  • 柳州网站建设推荐:揭秘那些藏在本地企业背后的流量密码与避坑指南,为什么这3点你必须要知道
  • 周口网站建设73data深度解析:为何中小企业主应该关注专业的互联网营销解决方案,揭秘行业背后那些不为人知的真相与服务细节
  • 武汉数据治理服务怎么选?本地服务商分析与推荐
  • 如何用embyToLocalPlayer打破浏览器沙盒限制,实现媒体服务器与本地播放器的无缝桥接
  • 成都有实力的网站建设:拒绝套路,只做能帮企业真正赚钱的官网,这才是成都做网站公司的良心之选
  • FAB智能化的下一站:从自动化到自主决策