一、算法分析
(1)思路——滑动窗口
- 我们在数组nums 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引区间 [left, right] 称为一个「窗口」。
- left不动,不断地增加 right 指针扩大窗口,直到窗口符合要求(窗口内数值之和>=target)。
- 此时,我们停止增加 right,转而不断增加 left 指针缩小窗口 ,直到窗口不再符合要求。
- 重复第 2 和第 3 步,直到 right 到达数组末尾。
(: 第 2 步相当于在寻找一个「可行解」,然后第 3 步在优化这个「可行解」,最终找到最优解,也就是最短的覆盖子串。左右指针轮流前进,窗口大小增增减减,窗口不断向右滑动,这就是「滑动窗口」。)
这里参考:labuladong大佬的算法小抄
(2)时间复杂度
该算法的时间复杂度是O(n)。
不要见到两个循环嵌套就以为时间复杂度是O(n^2),
时间复杂度主要是看每一个元素被操作的次数,每个元素在滑动窗口往右扩大时进来一次,窗口缩小时出去一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
二、参考代码
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int numsSize = nums.size();
if (numsSize == 0) return 0;//判断数组是否为空
int resMin = INT_MAX;
/*
resMin表示最终取的符合条件的最短的子数组长度.
INT_MAX是C++中的常量,表示int型的最大值,包含在头文件limits.h中.
这样才能不断更新取所有窗口长度的最小值
*/
int left = 0, right = 0;
//左右指针,滑动窗口的左右两端
int sum = 0, subLen = 0;
//窗口数值之和, 窗口的长度
while (right < numsSize) {
//left不变,right右移扩大窗口,直到满足要求进入下面的while循环
sum += nums[right];
//满足要求之后left右移缩小窗口优化这个解,直到不满足要求
while (sum >= target) {
subLen = right - left + 1;
//先计算出当前滑动窗口的长度
//再和resMin作比较,若sublen更小则更新resMin
resMin = subLen < resMin ? subLen : resMin;
//也可以写成resMin = min(subLen, resMin);
sum -= nums[left++];
}
right++;
//若此时窗口不满足要求(不会进入while循环)则right++扩大窗口
//若满足要求找到一个优化解之后right右移继续往后找更多解
}
return resMin == INT_MAX ? 0 : resMin;
//若resMin未改变说明数组中不存在符合条件的子数组
}
};