题目链接:
题目描述:

题目示例:

【从前往后】枚举数组中的任意一个元素,把它当成起始位置。然后从这个【起始位置】开始,然后寻找一段最短的区间,使得这段区间的和【大于等于】目标值。
将所有元素作为起始位置所得的结果中,找到【最小值】即可。
--代码这里就不演示了
由于此问题分析的对象是【一段连续的区间】,因此可以考虑【滑动窗口】的思想来解决这道题
让滑动窗口满足:从 i 位置开始,窗口内所有的和小于 target (那么当窗口内元素之和第一次大于等于目标值的时候,就是 i 位置开始,满足条件的最小长度)
做法:将右端元素划入窗口之中,统计出此时窗口内元素的和:
为何滑动窗口可以解决问题,并且时间复杂度更低?
这个窗口寻找的是:以当前窗口最左侧元素(记为 left)为基准,符合条件的情况。也就是在这道题中,从 left 开始,满足区间和 sum>=target 时的最右侧(记为 right)能到哪里
我们既然已经找到从 left 开始的最优的区间,那么就可以大胆舍去 left。但是如果继续像方法一一样,重新开始统计第二个元素(left2)往后的和,势必会有大量重复的计算(因为我们在求第一段区间的时候,已经算出很多元素的和了,这些和是可以在计算下次区间和的时候用上的)
此时,right1的作用就体现出来了,我们只需要将 left1 这个值从 sum 中剔除。从 right1 这个元素开始,往后找满足 left2 元素的区间 (此时 right1 也有可能是满足的,因为 left1 可能很小。sum 剔除掉 left1 之后,依旧满足大于等于 target )。这样我们就能省掉大量重复的计算
时间复杂度:虽然代码是两层循环,但是我们的 left 指针和 right 指针都是不回退的,两者最多都往后移动 n 次。因此时间复杂度是 O(N)
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums)
{
int n=nums.size(),sum=0,len=INT_MAX;
for(int left=0,right=0;right<n;right++)
{
sum+=nums[right];//进窗口
while(sum>=target)//判断
{
len=min(len,right-left+1);//更新
sum-=nums[left++];
}
}
return len==INT_MAX?0:len;
}
};博主笔记(字迹有点丑,请大家见谅):

题目链接:
题目描述:

题目示例:

枚举【从每一个位置】开始往后,无重复字符的子串可以到达什么位置。找到其中长度最大的即可。
在往后寻找无重复子串能到达的位置时,可以利用【哈希表】统计出字符出现的频次,来判断什么时候子串出现了重复元素
研究的对象依旧是一段连续的区间,因此继续使用【滑动窗口】思想来优化。
让滑动窗口满足:窗口内所有元素都是不重复的
做法:右端元素 ch 进入窗口的时候,哈希表统计这个字符的频次:
class Solution {
public:
int lengthOfLongestSubstring(string s)
{
int hash[128]={0};
int n=s.size(),left=0,right=0,ret=0;
while(right<n)
{
hash[s[right]]++;
while(hash[s[right]]>1)
{
hash[s[left++]]--;
}
ret=max(ret,right-left+1);
right++;
}
return ret;
}
};博主笔记(字迹有点丑,请大家见谅):

往期回顾:
【优选算法必刷100题】第001~002题(双指针算法):移动零、复写零问题
【优选算法必刷100题】第003~004题(双指针算法):快乐数和盛水最多的容器
【优选算法必刷100题】第005~006题(双指针算法):有效三角形的个数和查找总价值为目标值的两个商品
【优选算法必刷100题】第007~008题(双指针算法):三数之和,四数之和
总结:本篇博客介绍了两个滑动窗口算法实战题解:209.长度最小的子数组和3.无重复字符的最长子串。针对第一题,通过暴力解法和滑动窗口对比,详细解释了滑动窗口的高效原理,即通过左右指针不回退降低时间复杂度。第二题同样采用滑动窗口,利用哈希表统计字符频次来检测重复。如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持