1,窗口大小不变(求取窗口移动中窗口内的最大值和最小值)
int a[N],q[N]ans[N];
void dd(int x,int y){
int c=0;
int n=x,k=y;
int hh = 0,tt = -1;
for(int i=1;i<=n;i++)
{
a[i]=s[i];
while(hh <= tt and i - k >= q[hh]) hh++;
while(hh <= tt and a[q[tt]] >= a[i]) tt--; //把a[q[tt]] >= a[i]变成a[q[tt]] <= a[i]后,就变成求最大值
q[++tt] = i;
if(i>=k)ans[++c]=a[q[hh]];
}
}
//传进来x个数,每y个数是一个窗口
//ans记录每个窗口的最小值
例题154. 滑动窗口(acwing)
给定一个大小为 n≤106的数组。
有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。
你只能在窗口中看到 k个数字。
每次滑动窗口向右移动一个位置。
以下是一个例子:
该数组为 [1 3 -1 -3 5 3 6 7]
,k 为 3。
窗口位置 | 最小值 | 最大值 |
---|---|---|
[1 3 -1] -3 5 3 6 7 | -1 | 3 |
1 [3 -1 -3] 5 3 6 7 | -3 | 3 |
1 3 [-1 -3 5] 3 6 7 | -3 | 5 |
1 3 -1 [-3 5 3] 6 7 | -3 | 5 |
1 3 -1 -3 [5 3 6] 7 | 3 | 6 |
1 3 -1 -3 5 [3 6 7] | 3 | 7 |
你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。
输入格式
输入包含两行。
第一行包含两个整数 n 和 k,分别代表数组长度和滑动窗口的长度。
第二行有 n 个整数,代表数组的具体数值。
同行数据之间用空格隔开。
输出格式
输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。
输入样例:
8 3
1 3 -1 -3 5 3 6 7
输出样例:
-1 -3 -3 -3 3 3
3 3 5 5 6 7
代码实现
#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],q[N],ans[N],s[N];
int a1[N],q1[N],ans1[N],s1[N];
void minn(int x,int y){
int c=0;
int n=x,k=y;
int hh=0,tt=-1;
for(int i=1;i<=n;i++){
a[i]=s[i];
while(hh<=tt&&i-k>=q[hh])hh++;
while(hh<=tt&&a[q[tt]]>=a[i])tt--;
q[++tt]=i;
if(i>=k)ans[++c]=a[q[hh]];
}
}
void maxx(int x,int y){
int c=0;
int n=x,k=y;
int hh=0,tt=-1;
for(int i=1;i<=n;i++){
a1[i]=s[i];
while(hh<=tt&&i-k>=q1[hh])hh++;
while(hh<=tt&&a1[q1[tt]]<=a1[i])tt--;
q1[++tt]=i;
if(i>=k)ans1[++c]=a1[q1[hh]];
}
}
int main(){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>s[i];
minn(n,k);
maxx(n,k);
for(int i=1;i<=n-k+1;i++){
cout<<ans[i]<<' ';
}
cout<<endl;
for(int i=1;i<=n-k+1;i++){
cout<<ans1[i]<<' ';
}
cout<<endl;
return 0;
}
2,窗口大小改变(对特定子串的求取
例;
求最长不重复子串
string a[N];
map<string,int>s;
int ans = 0;
int head = 0; //head为头指针
for (int i = 0; i < n; i++) { //i为末指针
head = max(head, s[a[i]]); //当一个元素出现两次时,更新头指针,t直接更新到上一个
// a[i]的位置。
s[a[i]] = i + 1; //记录每个元素位置的下一个位置,方便更新头指针
ans = max(ans, i - head + 1); //每次更新最大值
}
)