#209
中等
低频
滑动窗口长度最小的子数组
这是一道围绕数组展开的高频练习。建议先掌握「滑动窗口」这套写法,再结合下方步骤讲解理解状态维护、边界处理和复杂度取舍。
数组
题目分析
给你一个正整数数组和一个目标值 target。
要求找出和大于等于 target 的最短连续子数组长度。如果不存在,就返回 0。
一句话概括:
窗口和一旦达到目标,就马上尝试收缩到最短。
接下来怎么看推荐代码: 带着这个理解再看推荐代码时,重点观察这条主线:右指针扩张累计区间和,一旦和达到目标,就尽量左缩窗口并更新最短长度。
推荐代码
推荐解法:滑动窗口
时间复杂度: O(n)
空间复杂度: O(1)
核心思路: 右指针扩张累计区间和,一旦和达到目标,就尽量左缩窗口并更新最短长度。
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int sum = 0;
int answer = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= target) {
answer = Math.min(answer, right - left + 1);
sum -= nums[left];
left++;
}
}
return answer == Integer.MAX_VALUE ? 0 : answer;
}
}结构化讲解
面试时怎么讲
开场思路
这题我会用滑动窗口,因为数组全是正数,窗口和具备单调性。
核心过程
- 右指针不断扩张窗口并累加当前和。
- 一旦窗口和达到目标,就尝试左缩窗口。
- 每次左缩前都更新当前最短合法长度。
- 最终返回最短长度,若从未满足则返回 0。
复杂度总结
时间复杂度 O(n),空间复杂度 O(1)。
面试补一句:正数数组是这题能用滑动窗口的根本原因。
核心思路
因为数组元素全是正数,窗口和随着右移只会变大,随着左缩只会变小,所以滑动窗口可以稳定地找到最短满足条件的连续子数组。
步骤讲解
1
右指针扩张窗口累计和
不断把右侧元素加入窗口,更新当前区间和。
为什么这样做:先让窗口达到“和至少为 target”的合法状态。
对应代码提示:sum += nums[right];
2
窗口合法后尽量左缩
当当前和已经达到目标值时,持续移动左指针,并更新最短答案。
为什么这样做:题目要求的是最短长度,所以合法后要马上尝试缩小窗口。
对应代码提示:while (sum >= target) { answer = Math.min(answer, right - left + 1); ... }
3
遍历结束后返回最优结果
如果从未找到合法窗口,返回 0;否则返回记录的最短长度。
为什么这样做:并非所有数组都一定存在满足条件的子数组。
对应代码提示:return answer == Integer.MAX_VALUE ? 0 : answer;
易错点
没利用数组全为正数
这是滑动窗口成立的前提,若有负数就不能这么收缩。
正确理解:明确题目保证正整数数组,窗口和具备单调性。
窗口合法后没有立即左缩
会错过更短的可行子数组。
正确理解:一旦
sum >= target,就进入内层循环持续收缩。未找到答案时返回极大值
初始化值只是哨兵,不是有效长度。
正确理解:结束后如果答案未更新,返回 0。
复杂度与适用判断
时间复杂度:O(n)
空间复杂度:O(1)
比其他方案更好在哪里:比暴力枚举所有子数组快得多,把复杂度从平方级降到了线性级。
适用判断:正数数组中出现“最短/最长连续区间满足和约束”时,优先考虑滑动窗口。
额外提醒
- 右扩负责变合法,左缩负责变最优。