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

【滑动窗口专题】第一讲:长度最小的子数组

🌿 伸缩窗口,快速捕捉满足条件的最短区间,滑动窗口的精髓由此揭开序幕。

🌱 文章摘要

本篇作为「滑动窗口专题」的开篇,带你从一道经典的数组题出发,理解滑动窗口的核心思想:通过左右指针的“扩张—收缩”操作,在 O(n) 的时间复杂度内快速捕捉满足条件的最短区间。这道题是后续多种字符串和数组窗口题的基础。


🌊 在正式开启滑动窗口之前,如果你还没看过我的《双指针专题》

👉双指针专题_明天会有多晴朗的博客-CSDN博客,强烈推荐从那里起航 🚀
那里从最基础的「移动零」到进阶的「四数之和」,能帮助你更顺畅地理解窗口技巧的演变过程


🧭 导读

“双指针专题”中,我们熟悉了“固定+移动”的技巧。而进入“滑动窗口专题”后,问题的核心从“数值对撞”转变为“区间伸缩”

本篇,我们将从一道非常经典的题目——长度最小的子数组(Minimum Size Subarray Sum)入手,掌握「何时扩张窗口,何时收缩窗口」的基本套路,为后续的《无重复字符的最长子串》《最小覆盖子串》等打下坚实的基础


一、题目描述

题目:
给定一个含正整数的数组 nums 和一个正整数 target,找出该数组中满足 和 ≥ target最短连续子数组,并返回其长度;如果不存在,返回 0。

示例:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 的和 ≥ 7,且长度最短。

二、思路引导:滑动窗口的“扩张—收缩”

1. 直觉与关键观察

  • 题目要求连续子数组且数组元素为正数。这两个条件非常关键:连续保证我们可以用两个指针表示一个窗口;正数保证当我们把窗口右端向右移动时,窗口和只会单调不减,把左端向右移动时窗口和只会单调不增

  • 因此,维护一个 [left, right] 的窗口,右端向右扩张来尝试“满足条件”,一旦满足就尽量收缩左端以尝试得到更短区间——这是一个贪心且不会错过最优解的策略。

2. 为什么“右扩后左缩”不会漏解?

  • 设我们固定某次扩到 right = r,此时窗口 [L, r] 首次满足 sum ≥ target(含首次情况或后续某次)。
  • 因为所有元素为正,若我们在 L 之前有更大的 L' < L 使 [L', r] 满足条件,那么当右指针第一次到达 r 时,[L', r] 也会已被考虑过(因为左指针只会向右移动)。
  • 反过来也成立:当窗口满足条件并尝试缩左时,任何缩左后依旧满足条件的更短子区间都会被检测并更新答案。
  • 因此该策略不会漏掉任何可能的最短窗口。

3. 与暴力法的对比

  • 暴力枚举所有 (i, j) 对计算和 → O(n²)(或更差),不够高效。
  • 滑动窗口用单次线性扫描,左/右指针合计移动次数 ≤ 2n → O(n),在数组元素为正时是最优的常用方案。

三、窗口变化示意

数组:[2, 3, 1, 2, 4, 3]target = 7

Step 1: right = 0, sum = 2 < 7 → 右移 right
[2] 3 1 2 4 3^Step 2: right = 1, sum = 5 < 7 → 继续右移
[2 3] 1 2 4 3^   ^Step 3: right = 2, sum = 6 < 7 → 继续右移
[2 3 1] 2 4 3^     ^Step 4: right = 3, sum = 8 ≥ 7 √ → 记录长度 4
→ 收缩 left,sum=8-2=62 [3 1 2] 4 3^     ^Step 5: right = 4, sum = 10 ≥ 7 → 记录长度 3
→ 收缩 left,sum=10-3=72 3 [1 2 4] 3^    ^Step 6: right = 4, sum = 7 ≥ 7 → 记录长度 2
→ 收缩 left,sum=7-1=6  ×Step 7: right = 5, sum = 6+3=9 ≥ 7 → 更新长度
→ 收缩 left,找到最短长度 2([4,3])

核心:每个元素进窗口一次、出窗口一次,总复杂度 O(n)


四、代码实现(C++)

#include <vector>
#include <climits>
using namespace std;class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int n = nums.size();int left = 0, sum = 0, ans = INT_MAX;for (int right = 0; right < n; ++right) {sum += nums[right];// 每次扩张后,尽量收缩左边以寻找更短区间while (sum >= target) {ans = min(ans, right - left + 1);sum -= nums[left++];}}return ans == INT_MAX ? 0 : ans;}
};

五、代码剖析与细节问题

1. 每个指针的移动次数为何是 O(n)

  • 右指针 right 在主循环中最多移动 n 次(从 0 到 n-1)。

  • 左指针 left 在内部收缩循环中也至多移动 n 次(每次收缩都使 left 增加),left 永远不会回退。
    → 因此总指针移动次数 ≤ 2n,算法为 O(n)。

2. 为什么要求数组中的元素为正数?

  • 若元素均为正数,窗口扩张会使 sum 单调递增,收缩会使 sum 单调递减;这使得我们可以用两指针做贪心判断并保证正确性。

  • 若存在负数,收缩可能导致 sum 增大或扩张导致 sum 减小,单调性被破坏,滑动窗口策略需要调整。

3. 关于溢出与数据类型

  • nums 元素与 target 较大(比如题目允许 10^9),sum 可能溢出 int。在这种极端场景下,应使用 long long sum

  • 在多数题目约束下 int 足够,但写通用代码时用 long long 更保险。

4. 常见错误

  • right++ 放在错误位置导致漏算当前窗口;推荐不要把 right++ 放在收缩循环内部。

  • 忘记处理 ans 未更新的情况(返回 0)。

  • 使用 INT_MAX 然后做 ans + 1 等操作可能溢出,推荐比较并在最后判断。

  • 当需要输出索引时,务必在更新 ans 前记录 left/right 的当前值,否则 left 会在收缩后改变。


六、复杂度分析

  • 时间复杂度

O(n)right 从 0 增到 n-1left 从 0 也最多增到 n-1。每个元素最多进窗口一次、出窗口一次。所谓“摊还分析” (amortized analysis):虽然有嵌套的 while,但内部 while 的总执行次数不会超过 n,因此总复杂度线性。

  • 空间复杂度

O(1):使用固定数量的整数变量 left/right/sum/ans 等。若你还要返回子数组内容或索引,额外开销为 O(1)(只是几个索引)或 O(k)(若复制子数组内容则为其长度 k)。


七、总结

  • 本题是滑动窗口的入门经典:熟练掌握「右扩→左缩」的节奏与“单调性”前提(元素为正)是关键。
  • 代码实现简洁,但细节(收缩时机、边界处理、类型溢出、返回值约定)会决定你是否通过面试题与线上判题。
  • 掌握后,向字符串类和更复杂的“窗口状态维护”题(字符计数、频率表、单调队列)顺利过渡将变得非常自然。

🔜 下一讲预告

下一篇我们将进入《无重复字符的最长子串》,这是一道经典的字符串型滑动窗口题

  1. 窗口如何动态维护字符出现次数?
  2. 如何在扩张和收缩之间平衡窗口长度?

下一讲我们将逐步拆解并给出高效实现 !


📚 系列更新提示

本文是《滑动窗口专题》第 1 篇
接下来我们将从「最短子数组」出发,逐步攻克字符串、数组中的各种滑动窗口题目,让你真正掌握“窗口的伸缩与状态维护”这项算法利器。

📌 系列持续更新中,欢迎 点赞、收藏、关注,不要错过每一次窗口技巧的进阶!🚀

http://www.dtcms.com/a/461546.html

相关文章:

  • 软考-系统架构设计师 基于架构的软件开发方法详细讲解
  • 电子电气架构 --- 操作系统的基本概念
  • 苏州做网站公司电话wordpress资源分享网
  • 手机能建设网站企业的做网站
  • Unity笔记(十一)——换装、Spine骨骼动画、3D动画相关
  • 面向汽车网络安全的轻量级加密技术
  • 《投资-114》价值投资者的认知升级与交易规则重构 - 从大规模分工的角度看,如何理解“做正确的事”,即满足下游正确的需求
  • 添加一路AXI总线对DDR进行读写时,XDMA测试不通过
  • 基于python的机器学习(十)—— 评估算法(三)
  • 男女做那个的的视频网站检察院门户网站建设成效
  • Oracle的SID是什么
  • Oracle大会临近,23ai 本地版会发布吗?
  • 【Python刷力扣hot100】11. Container With Most Water
  • 通信建设网站做网站主页上主要放哪些内容
  • 《常用 IDL(接口定义语言)详解与对比》
  • 做二手房产网站多少钱河南建设工程信息网站
  • K230基础-获取触摸坐标
  • Linux应用--网络编程
  • 鸟哥的Linux私房菜 第三部分: 学习shell与shell script
  • 鸿蒙中 UDP 数据包发不出去?一文教你从权限到代码彻底排查!
  • 前端小白学习路线(参考)
  • 大连工业大学图书馆网站建设优化培训班
  • 浅谈 富文本编辑器
  • 有手机网站了还要微网站吗设计平台兼职
  • **发散创新:状态函数在编程中的深度应用与实现**在编程领域,状态函数是一个核心概
  • 【OCR】PaddleX
  • Python 元组与集合详解
  • 微信小程序的页面生命周期 以及onShow的应用场景
  • 微信小程序入门学习教程,从入门到精通,微信小程序核心 API 详解与案例(13)
  • 企业建站系统知识库管理系统方案