有关滑动窗口类型的题目都记录在此~持续更新
文章目录
笔记
滑动窗口算法广泛应用于网络协议等,滑动窗口算法是一种思路,可以解决很多问题,比较适合滑动窗口解决的问题通常是题目要求连续的情况。
滑动窗口主要用来处理连续问题。比如题目求解“连续子串 xxxx”,“连续子数组 xxxx”,就应该可以想到滑动窗口。能不能解决另说,但是这种敏感性还是要有的。
类型主要有:
- 固定窗口大小
- 窗口大小不固定,求解最大的满足条件的窗口
- 窗口大小不固定,求解最小的满足条件的窗口(上面的 209 题就属于这种)
后面两种统称为可变窗口。当然不管是哪种类型基本的思路都是一样的,不一样的仅仅是代码细节。
解题的套路通常是建立一个数组来表示滑动窗口,然后不断更新滑动窗口的范围(通常是往后移动),解题的不同点其实就在于如何更新滑动窗口的范围而已。
伪代码
初始化慢指针 = 0
初始化 ans
for 快指针 in 可迭代集合
更新窗口内信息
while 窗口内不符合题意
扩展或者收缩窗口
慢指针移动
更新答案
返回 ans
练习题目
209. 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
- 解题思路:
定义左右指针控制滑窗大小,先初始化左右指针都为0,然后不断移动右指针扩大窗口直到满足窗口内元素之和大于target,当存在满足的情况时,保留最小的窗口长度,然后尝试压缩窗口(左指针右移),然后再重复上诉不揍即可。由于右指针一旦指向最后一个元素,则循环终止,因此其时间复杂度时O(n)级别,左右指针最多各移动n次(即数组每个元素都不小于target),空间复杂度O(1)。
- Java
public class 长度最小的子数组209 {
static class Solution {
public int minSubArrayLen(int target, int[] nums) {
int min=nums.length+1;
//定义左右指针,还有指针之间元素之和
int l=0,r=0,sum=0;
//下面就是可变滑窗的实现
for (r = 0; r < nums.length; r++) {
sum+=nums[r];
//当满足条件后,尝试压缩窗口
while (sum>=target) {
//先更新下最小长度
min=Math.min(min, r-l+1);
//然后窗口右移
sum-=nums[l];
l+=1;
}
}
return min==(nums.length+1)?0:min;
}
}
public static void main(String[] args) {
Solution s=new Solution();
int nums[]={2,3,1,2,4,3};
int target=7;
System.out.println(s.minSubArrayLen(target, nums));
}
}
- C++
#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int min = nums.size() + 1;
//定义左右指针,还有指针之间元素之和
int l = 0, r = 0, sum = 0;
//下面就是可变滑窗的实现
for (r = 0; r < nums.size(); r++) {
sum += nums[r];
//当满足条件后,尝试压缩窗口
while (sum >= target) {
//先更新下最小长度
min = min>(r - l + 1)?(r - l + 1):min;
//然后窗口右移
sum -= nums[l];
l += 1;
}
}
return min == (nums.size() + 1) ? 0 : min;
}
};
#if 1
int main() {
Solution s ;
vector<int> nums = { 2,3,1,2,4,3 };
int target = 7;
cout << s.minSubArrayLen(target, nums) << endl;
return 0;
}
#endif //