滑动窗口变长窗口正整数数组最短连续子数组
LC209 · 长度最小的子数组
给你一排正整数,找一段最短的连续区间,使这段区间的和至少达到 target。
看懂题目到底在问什么
理解什么是连续子数组
理解为什么正整数数组可以用滑动窗口
掌握右扩、左缩、更新答案的完整流程
能用 Go 代码写出解法
题目到底在问什么?
target = 7
nums = [2,3,1,2,4,3]
目标:找一个连续子数组,使它的和 >= 7,并且长度尽可能短。
[2,3,1,2] 的和是 8,长度是 4,可以。
[4,3] 的和是 7,长度是 2,也可以。因为 2 更短,所以答案是 2。
本题不是随便挑几个数字相加,而是必须取原数组中连续的一段。
先看暴力法为什么慢
[2]
[2,3]
[2,3,1]
[2,3,1,2]
...
暴力法会枚举所有起点和终点。这样会重复计算很多区间,时间复杂度是 O(n²)。 我们需要一种能复用窗口 sum 的方法。
为什么能用滑动窗口?
因为 nums 全是正整数
- 右边加入一个数,sum 一定变大
- 左边移出一个数,sum 一定变小
策略很自然
- sum < target:右扩,让窗口变大
- sum >= target:记录答案,然后左缩,尝试变短
动画主区域
伸缩探照灯:窗口沿数组轨道移动
Step 0 / 11
速度
index 0
index 1
index 2
index 3
index 4
index 5
2
3
1
2
4
3
sum 能量槽sum = 0 / target = 7
状态字段
target 7
left 0
right -
sum 0
best 当前最短记录
∞
只在 sum >= target 时尝试更新
当前动作
窗口为空
当前解释
右指针准备从左到右扫描数组。
代码联动区
Go 代码高亮动画
1func minSubArrayLen(target int, nums []int) int {2left := 0// 窗口左边界从 0 开始3sum := 0// sum 记录当前窗口和4ans := len(nums) + 1// 先放一个不可能的最大答案 6for right, x := range nums {7sum += x// right 右扩时高亮:把新数字纳入窗口 9for sum >= target {// 达标后不是 if,而是 while/for 连续左缩10length := right - left + 111if length < ans {12ans = length// 先更新答案,再移动 left13} 15sum -= nums[left]// 左缩:把左端元素移出窗口16left++17}18} 20if ans == len(nums)+1 {21return 022} 24return ans25}right 右扩时,高亮 sum += x。
sum >= target 时,高亮 for sum >= target。
更新答案时,高亮 length 和 ans 更新逻辑。
左缩时,高亮 sum -= nums[left] 和 left++。
卡片 1
为什么 right 不回头?
因为每个元素只需要进入窗口一次。right 负责扩张,left 负责收缩,两个指针都只向右走。
卡片 2
为什么时间复杂度是 O(n)?
虽然有两层循环,但每个元素最多被 right 加入一次,被 left 移出一次,所以总操作次数是线性的。
卡片 3
为什么数组有负数就不行?
因为有负数时,右扩 sum 不一定变大,左缩 sum 不一定变小,滑动窗口的判断依据会失效。
面试怎么说
这题因为数组元素都是正整数,所以可以用变长滑动窗口。右指针不断扩张窗口并累加 sum。 当 sum >= target 时,说明当前窗口已经满足条件,先更新最短长度,然后移动左指针尝试缩短窗口。 由于每个元素最多进窗口一次、出窗口一次,所以时间复杂度是 O(n),空间复杂度是 O(1)。
常见错误
- 1. 忘记在 sum >= target 时用 while,而不是 if。
- 2. 先移出 left 再更新答案,导致漏掉合法窗口。
- 3. 没处理不存在答案的情况。
- 4. 没意识到本题依赖“正整数”条件。
- 5. 把连续子数组误解成任意挑几个数。
交互式练习
1
target =4
nums =[1, 4, 4]
最短长度是多少?
2
target =11
nums =[1, 1, 1, 1, 1, 1, 1, 1]
最短长度是多少?
3
为什么 nums 有负数时不能直接套这个滑动窗口?
💡 提示
完成这些练习题可以帮助你更好地理解滑动窗口的核心机制和适用条件。 如果遇到困难,可以回顾上面的动画和理论讲解。