前言
🌟🌟本期讲解关于滑动窗口问题~~~
🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客
🔥 你的点赞就是小编不断更新的最大动力
🎆那么废话不多说直接开整吧~~
目录
📚️1.长度最小的子数组
1.1题目描述
本题是在一个数组内找到连续且长度最小并且数组内的和大于target数值,题目的描述如下所示:
解释:
此时的要求就是在一个数组内,找到连续的子数组(长度最小,元素的和大于目标数值),那么此时就是返回这里的最小长度即可;
1.2题目解析
1.暴力枚举
具体的思路就是:
第一步:定义两个指针(这两个指针就是表示的左右子数组的边界),然后两个指针的初始位置都是0;
第二步:将这里的right指针向每次后移动一个单位后,进行判断是否大于这里目标值;
第三步:判断是否大于这里的值后,若大于则更新我们需要的两个指针之间的长度,若小于就继续向后进行移动;(每一次更新要进行取最小值)
第四步:最后进行循环的跳出,边界的判定的操作,最后返回最终的长度
效果如下图所示:
解释:
这就是第一次循环,left不变,然后right不断向后移动,时刻更新这里的len长度,最后知道出界,然后进入外部循环;
**解释:**此时就是进入外部循环,然后right与left同一个索引的位置;
**注意:**更新我们需要的长度的时候要注意,这里的两个边界里的元素的和是否大于或等于我们需要的目标值,并且每次更新要取最小的一个长度,这里设计大小比较;
2.滑动窗口
这里的滑动窗口的概念其实就是双指针,并且对于上面的暴力枚举进行了优化的操作,那么具体的思路就是如下所示:
在暴力枚举的操作的情况下,我们发现当子数组内的元素之和已经大于了目标值了,那么此时right就不用向后面走了(因为后面再加肯定大于目标值,但是长度一直在增加,但是这里要最小的),然后left就可以向前走了,若此时数据变小right继续往后面走,此时就会发现,right和left两个指针一直前进;
此时两者都往前面进行移动,包含的元素,然后就像一个窗口向后面滑动一致;所以叫"滑动窗口"
具体的画面如下:
解释:
为啥大于目标值right不更新位置:因为right在满足条件后, right再往后移动,确实是满足大于target的条件,但是我们这里的求最小的长度,后面就是无效遍历;
为啥小于目标值left不更新位置:因为这里的值本来就小于了这里的值,left移动不就更小了吗;
1.3代码实现
具体的代码实现如下所示:
java
class Solution {
public int minSubArrayLen(int target, int[] nums) {
// 设置两个指针
int left = 0;
int right = 0;
int sum = 0;
int len = nums.length+1;
// 开始进行循环
for (; right < nums.length; right++) {
sum += nums[right];
while (sum >= target) {
len = Math.min(len,right - left + 1);
// 如果此时进行的值大,出窗口
sum -= nums[left];
left++;
}
}
if(len == nums.length+1){
return 0;
}else{
return len;
}
}
}
解释:
具体的意思,sum就是代表这里的每一步的和,然后当这里的sum大于目标值后就进行判断更新这里的len的大小(取小的)然后此时left移动后,left和right之间的数值就是sum减去left没移动之前的数;
最后为了出现所有的值都不大于目标值,那么就直接返回0,否则返回我们拿到的len子数组的长度的值即可;
时间复杂度
这里一看就是两个循环,那么时间复杂度就是O(n^2),但是这里的两个指针都往前面移动,且不会回头,那么这里的时间复杂度就是O(N+N),最终的时间复杂度就是O(N)
📚️2.无重复字符最长子串
2.1题目描述
这里的题目要求和上面的几乎是一致的,大致就是找最长的子数组(子数组里没有重复的元素);
题目如下:
实例:
一个数组: a b c a b c b b
输出结果:3
最长子数组:[ a b c ]
解释:和上面的题目基本一致,就是返回找到的最长的子数组,然后返回这个子数组的长度即可
2.2题目解析
1.暴力枚举
还是和上面的几乎是不差的,我们可以将这字符串转化为数组的形式,然后利用模拟hash的方式进行存储字母的个数,然后规定两端的指针,len进行比较,返回最大的长度;
大致的情况如下图:
解释:
就是每个字数粗都进行遍历,发现这里存在了重复的元素,那么len不会进行更改,right走完后,left加一,然后重复上述的操作;
2.滑动窗口
结题思路:
大致就是对上述暴力枚举的提升,当这里发现出现重复的时候,right再向后面移动那么就会一直出现重复的元素,所以此时right向后枚举就是无用的,此时就要left向后移动,直到没有重复的元素,然后right再向后面移动,(要更新符合要求的子数组的长度)
如下图所示:
解释:
为啥right不向后面重新枚举,假如此刻重上述中left的位置开始向后面移动,那么这里就是[ b ] [ b c ] ,[ b c a];哎此时就是不用向后移动的原因,len还是会重1更新成3;所以right不用向后重新遍历枚举;
2.3代码实现
具体的代码如下所示:
java
class Solution {
public int lengthOfLongestSubstring(String s) {
char[] arr=s.toCharArray();
//hash数组
int[] hash=new int[128];
int left=0,right=0,len=0;
while(right < arr.length){
//放到hash表里
hash[arr[right]]++;
while(hash[arr[right]] > 1){
//将数据移出hash表
hash[arr[left]]--;
left++;
}
len=Math.max(len,right-left+1);
right++;
}
return len;
}
}
解释:
这里就是通过hash表的方式判断元素的数量,(hash是通过索引代表的每个元素,128可以代表所有的元素),然后就是right先移动,判断出现是否重复后,在将left位置元素去掉,然后left向后移动;每次移动要判断是否没有了重复的元素;
当然要注意更新len的长度,但是注意了:"right++,和长度的更新,要注意位置,否则长度会多1"
时间复杂度:和上面时间复杂度是一致的都是O(N);
📚️3.总结
上述的两道题主要概括:
right移动看做是进窗口,left移动是出窗口:其实就是进窗口后判断什么时候出窗口,然后按要求更新出窗口之前的长度,继续进窗口,就是一个循环而已~~·
本期主要讲解了双指针优化,滑动窗口的实现;解决了"长度最小的子数组""无重复字符最长子串"两题;
第一题:LCR 008. 长度最小的子数组 - 力扣(LeetCode)
第二题:3. 无重复字符的最长子串 - 力扣(LeetCode)
🌅🌅🌅~~~~最后希望与诸君共勉,共同进步!!!
💪💪💪以上就是本期内容了, 感兴趣的话,就关注小编吧。
😊😊 期待你的关注~~~