滑动窗口
给定一个含有 n 个正整数的数组和一个正整数 target。
找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 ,并返回其长度。如果不存符合条件的子数组,返回0。
示例 :
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
1、三层循环:
for (i=0;i<=len-1;i++) #起始位置 for(j=1;j<=len-1-i+1;j++) #取的长度 for(k=i;k<=i+j-1;k++) #终止位置
2、两层循环:
for(i=0;i<=len-1;i++){ #起始位置 ans=0; for(j=i;j<=len-1;j++){ #终止位置。相比于三层循环优化在于:累加便可算出起始位置到终止位置的和。无需多一层循环 ans+=nums[j]; if(ans>=target){ length=min(length,j-i+1); } } }
3、滑动窗口:
我的代码:不太清晰,但写了几次都是这个。当我们的值达到了目标值就开始从起始位置减,重复这个过程。
class Solution { public: int minSubArrayLen(int target, vector<int>& nums) { int len=nums.size(); int i,j,k; int ans=len; int ans1=0; int sum=0; for(j=0;j<=len-1;j++){ ans1+=nums[j]; } if(ans1<target){ return 0; } for(i=0,j=0;j<=len-1;){ while(sum<target&&j<=len-1){ sum+=nums[j++]; } while(sum>=target){ ans=min(ans,j-1-i+1); sum-=nums[i++]; } } return ans; } };
更为标准的代码:
class Solution { public: int minSubArrayLen(int target, vector<int>& nums) { int len=nums.size(); int i,j,k; int ans=0x3f3f3f3f; int ans1=0; int sum=0; i=0; for(j=0;j<=len-1;j++){ sum+=nums[j]; while(sum>=target){ ans=min(ans,j-i+1); sum-=nums[i++]; } } return ans==0x3f3f3f3f?0:ans; } };
时间复杂度:O(n)
空间复杂度:O(1)
为什么时间复杂度是O(n)?
不要以为for里放一个while就以为是O(n^2), 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
代码随想录真的贴心。
滑动窗口的要点:
1、明确有一个窗口开始端S,一个窗口终止端e。e是循环控制不断向后的,S是在当前情况满足题目条件后不断更新寻找最优。
滑动窗口的S端何时往后移动是一个比较关键的点。