滑动窗口¶
前置知识¶
双指针
目标¶
滑动窗口模板题
滑动窗口¶
双指针:以 r
为基础指针并根据题目要求来移动 l
或者保持 l
不动,同时 ans
由每一步的 r-l
来更新。
滑动窗口:以 l
为基础指针,并且 l~r
看做一个窗口,r
不断右移,根据题目要求来右移一次 l
或者保持 l
不动,特点是 r-l
始终不减,ans
为最终的 r-l
。
区别:双指针算法当需要移动 l
指针时,可能移动多个单位以满足要求。而滑动窗口算法当需要移动 l
指针时,每次必定只移动一个单位!
CF1955D Inaccurate Subsequence Search¶
https://codeforces.com/problemset/problem/1955/D
a数组中所有长度为m的子串,和b数组中的元素对比,至少有k个是相同的
看窗口内相同的元素的个数,是否>=k
#include <bits/stdc++.h>
using namespace std;
int T, n, m, k;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> T;
while (T--) {
cin >> n >> m >> k;
vector<int> a(n), b(m);
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < m; i++) cin >> b[i];
map<int, int> cnta, cntb;
for (int i = 0; i < m; i++) cntb[b[i]]++;
int cnt = 0, ret = 0;
for (int i = 0, j = 0; i < n; i++) {
while (i - j + 1 > m) {
cnta[a[j]]--;
if (cnta[a[j]] < cntb[a[j]]) cnt--;
j++;
}
if (cnta[a[i]] < cntb[a[i]]) cnt++;
cnta[a[i]]++;
if (i >= m - 1 && cnt >= k) {
ret++;
}
}
cout << ret << '\n';
}
return 0;
}
POJ2823 Sliding Window¶
// 结合了单调队列
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1e6 + 10;
int a[N], q[N], n, k;
int hh, tt;
int main(){
cin >> n >> k;
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
hh = 0, tt = -1;
for (int i = 0; i < n; i++){
// 窗口滑出去了
if (hh <= tt && i - k + 1 > q[hh]) hh++;
// 较小的值入队
while (hh <= tt && a[q[tt]] >= a[i]) tt--;
q[++tt] = i;
// 窗口是满的就输出,没满k宽度的时候,是不可输出的
// 队列是单调递增的,队头是窗口里的最小值
if (i - k + 1 >= 0) printf("%d ", a[q[hh]]);
}
puts("");
hh = 0, tt = -1;
for (int i = 0; i < n; i++){
// 窗口滑出去了
if (hh <= tt && i - k + 1 > q[hh]) hh++;
// 较小的值入队
while (hh <= tt && a[q[tt]] <= a[i]) tt--;
q[++tt] = i;
// 窗口是满的就输出,没满k宽度的时候,是不可输出的
if (i - k + 1 >= 0) printf("%d ", a[q[hh]]);
}
puts("");
return 0;
}
参考¶
- https://blog.csdn.net/lyqptp233/article/details/113774583 算法系列--滑动窗口与双指针
- https://www.acwing.com/solution/content/240594/