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。
实现
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 时,代码先记录长度,再尝试移除最左侧元素。由于元素为正数,移除后和会变小;在窗口失效之前,每次记录的都是以当前右端点结尾的可行窗口,并且不断收缩会找到其中最短的一个。右端点遍历所有位置,因此全局最短答案不会遗漏。
- 时间复杂度:,左右指针各自最多移动
n次。 - 空间复杂度:。
滑动窗口依赖元素为正数。若数组允许负数,窗口和在扩张或收缩时不再单调,这种双指针策略就不适用。
209. 长度最小的子数组:滑动窗口收缩求最短区间
https://blog.xqcherry.top/posts/algorithms/minimum-size-subarray-sum-sliding-window/ 目录