第一步:了解题意
给定一个数组,要求在这个数组中找到一个必须是连续的子数组并且这个子数组每个元素加起来>=target并从找到的这些数组中取一个最短的数组。
第二步:算法原理
滑动窗口是一种在序列(例如数组或链表)上解决问题的算法模式。它通常用于解决子数组或子字符串的问题,其中滑动窗口表示一个范围,这个范围在序列上移动,以便找到满足特定条件的子数组或子字符串。
算法的基本思想是维护两个指针,通常是左右两个指针,表示滑动窗口的左右边界。通过调整这两个指针,可以滑动窗口在序列上移动。在每个窗口位置,都可以根据问题的要求进行处理,比如计算窗口内的和、最大值、最小值,或者检测满足某些条件的子数组或子字符串等。
滑动窗口的模板:
1.left=0,right=0;
2.进窗口
3.判断
4.出窗口
更新结果(这是是在上面的4个步骤中根据题目的不同来穿插的)
学习算法我们要记住一个步骤就是面对一个题目的时候先想一下如何暴力的把他求出来,那么很简单那就是找到所有的子数组并从这些子数组中找到和>=target的数组之后取得最小值那么我们把暴力的方法先写出来代码如下:
👩🏻💻暴力解法
class Solution{
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int ans=INT_MAX;
for(int i=0;i<nums.size();i++)
{
int t=0;
for(int j=i;j<nums.size();j++)
{
t+=nums[j];
if(t>=target)
{
ans=min(ans,j-i+1);
break;
}
}
}
if(ans==INT_MAX)return 0;
else return ans;
}
};
由于力扣的后台测试数据比较小所以这个暴力的解法也可以过但是我们可以清楚的看到这个算法的时间复杂度达到了O(n^2)因此这个时间负责度还是比较高的因此我们有没有更简单的办法呢?
👩🏻💻滑动窗口
使用滑动窗口进行优化,
在这道题目中我们可以看到两个重要信息。
1、子数组必须是连续的
2、子数组的和需要>=target
那么我们可以想一下我们可以使用两个指针一个是left一个是right,当left和right之间的元素和小于target的时候就让right一直向右移动,当right和left之间的元素大于等于target的时候我们更新一下此时的长度是否为最短,然后再让left左移查看此时right和left的元素之和是否大于等于target如果是就继续上一步操作即继续更新我们的最短长度,一直到right和left之间的数据小于target为止之后再让right指针右移即可。
具体操作如下:
第三步:代码实现
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int left=0,right=0,sum=0;
int len=INT_MAX;
while(right!=nums.size())
{
sum+=nums[right];//进窗口(这里加了right对应的值,right还没有++)
if(sum<target)//判断
{
right++;
continue;
}
else
{
len=min(len,right-left+1);//更新数据
sum=sum-nums[left]-nums[right];//出窗口(需要给left和right对应值都删掉)
left++;
}
}
return len==INT_MAX?0:len;
}
};
我们可以从用时分布图清楚的看到我们的时间效率有了很大的提升。
希望今年是个平安快乐的一年。