今天我们来看一下这道力扣题目,难度中等
力扣链接:209.长度最小的子数组
题目描述:
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
提示:
1 <= target <= 10^9
1 <= nums.length <= 10^5
这道题我用两种思路来解答,一种是暴力求解,一种是滑动窗口。
暴力求解
我们可以用两个for循环两个指针i,j来初始化起始位置和终止位置,用来遍历指针
不断寻找符合条件的最小数组长度
代码如下:
cpp
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int sum=0;
int result=INT32_MAX;//用来存储满足条件的最小数组长度
int sublength=0;//定义一个子数组
for(int i=0;i<nums.size();i++){//初始化i为起始位置
sum=0;//
for(int j=i;j<nums.size();j++){//初始化j为终止位置
sum=sum+nums[j];//用来更新 前j个数的总和
if(sum>=target){//如果sum>=target,说明找到了一个满足条件的区间
sublength=j-i+1;//记录此时子数组的长度差,因为从零开始,所以+1
result=result<sublength?result:sublength;//比较如果小于最小数组长度,返回自己,否则返回更新的子数组长度
break;//我们找符合条件最短的子序列,所以一找到就退出条件
}
//如果sum<target就继续移动j
}
}//循环结束
return result==INT32_MAX?0:result;//如果result没有被赋值,返回0,说明没有符合条件的子序列
}
};
暴力求解的代码现在在力扣上已经超时了,大家看看就好。接下来的滑动窗口的思想是比较重要的。
滑动窗口
思路
上述暴力求解通过两个for循环遍历i,j,将所有符合条件的区间都列了出来,而滑动窗口用1个for循环遍历符合条件的区间。
滑动窗口类似于双指针法的一种,只不过这个过程类似于窗口,所以叫滑动窗口
所谓滑动窗口就是不断调节子序列的起始位置和终止位置,得出我们想要的结果。
那么问题来了,什么是窗口呢?初始位置,起始位置又是在哪里呢?
所谓窗口,就是在满足条件>=s的滑动时所形成的连续数组
因为只使用1个for循环,到底是初始化起始位置还是终止位置呢?我们假设初始化起始位置i,那么后面的终止位置要怎样遍历呢?就会又成为暴力求解了。
1.首先我们定义sum为总和,sublength为数组子长度,i为初始位置,都为0。定义result为最小数组子长度INT32_MAX。用来记录数组如果没有符合条件的情况。
2.接下来使用for循环来初始化终止位置为0,遍历这个数组。
3.将nums[j]逐个相加存到sum中。
4.然后判断条件当sum大于等于s时,那么更新sublength计算此时长度差,如果此时长度差大于最小数组长度差result时那么返回0,说明没有要找的,如果小于那么返回sublength。再用sum减掉nums[i]第一个元素后,i向前移动,j向后移动。(这步是滑动窗口的关键)
5.最后,当for循环结束了返回如果存在返回它的长度sublength,如果不存在符合条件的子数组,返回 0 。
完整代码
cpp
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int sum=0;//定义总和为0
int sublength=0;//定义最小子数组为0
int result=INT32_MAX; //定义一个数为存储数组最小子长度
int i=0;//定义初始位置i
for(int j=0;j<nums.size();j++){//定义终止位置
sum=sum+nums[j];//定义和为前j个数相加
while(sum>=target){
sublength=(j-i+1);//求出长度差,+1是因为从0开始
result=result<sublength?result:sublength;//如果最小长度差<最小子长度就把长度差赋值成最小的
sum=sum-nums[i];//用和减去第一个数,前移i,更新了区间数组,这步是滑动窗口的关键(不断变更)
i++;//前移i
}
}
return result==INT32_MAX?0:result;//如果结果等于原来的最小数组长度,那么就说明没找到,返回0,否则找到了新的满足条件的,就返回result
}
};
总结
滑动窗口比暴力时间复杂度降低很多,因为暴力是所有结果都遍历一遍来找长度最小的,而滑动窗口通过子序列长度和大小,不断调节子序列的长度。本道题需要好好消化一下,稍微难了一点,希望我的思路能够帮助到你们呀~