547 字
3 分钟
209. 长度最小的子数组:滑动窗口收缩求最短区间

题目要求在正整数数组 nums 中找到一个连续子数组,使它的元素和至少为 target,并返回满足条件的最短长度;如果不存在这样的子数组,返回 0。

题目链接:209. 长度最小的子数组

思路:扩大窗口,再收缩到最短#

用左右指针 l、r 表示当前窗口 [l, r],用 s 保存窗口内元素和。遍历时,右指针逐步向右移动,把新元素加入窗口。

  • 当 s < target 时,当前窗口还不满足要求,继续扩大窗口。
  • 当 s >= target 时,记录当前长度,然后从窗口左侧移除元素并右移 l,直到窗口和重新小于 target。

数组元素都是正数,因此扩大窗口时区间和只会增加,收缩窗口时区间和只会减少。每个指针都只向右移动,所有满足条件的最短窗口都能在收缩过程中被记录。

例如,target = 7、nums = [2,3,1,2,4,3]。窗口和首次达到 7 时是 [2,3,1,2],长度为 4;继续右移并收缩后,窗口 [4,3] 的和仍为 7,长度为 2,因此答案是 2。

实现#

Terminal window
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
int res = 1e9;
int l = 0;
int s = 0;
for(int r = 0; r < n; r ++ ) {
s += nums[r];
while(s >= target) {
res = min(res, r - l + 1);
s -= nums[l];
l ++;
}
}
return res == 1e9 ? 0 : res;
}
};

正确性要点与复杂度#

当窗口和达到 target 时,代码先记录长度,再尝试移除最左侧元素。由于元素为正数,移除后和会变小;在窗口失效之前,每次记录的都是以当前右端点结尾的可行窗口,并且不断收缩会找到其中最短的一个。右端点遍历所有位置,因此全局最短答案不会遗漏。

  • 时间复杂度:O(n)O(n),左右指针各自最多移动 n 次。
  • 空间复杂度:O(1)O(1)。

滑动窗口依赖元素为正数。若数组允许负数,窗口和在扩张或收缩时不再单调,这种双指针策略就不适用。

209. 长度最小的子数组:滑动窗口收缩求最短区间
https://blog.xqcherry.top/posts/algorithms/minimum-size-subarray-sum-sliding-window/
作者
xqcherry
发布于
2026-10-11
许可协议
CC BY-NC-SA 4.0