题目链接
https://www.acwing.com/problem/content/156/
题目
给定一个大小为n≤10^6的数组。
有一个大小为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
题解
单调队列的板子题。不过也可以用multiset做。单调队列复杂度O(n).multiset复杂度O(nlogn)
用数组模拟队列,q[maxn], hh表示队头,tt表示队尾。
初始化:hh=0,tt=-1. hh>tt队列为空,hh<=tt队列非空。
入队从队尾入: q[++tt]=i;
队列里放的是下标
求区间最小值那么维护队列单调严格递增,队头元素就是当前区间的最小值的数组下标
求区间最小值那么维护队列单调严格递减,队头元素就是当前区间的最大值的数组下标
单调队列代码
#include<algorithm>
#include <iostream>
#include<cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int a[maxn];
int q[maxn];
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++) scanf("%d",a+i);
int hh=0,tt=-1;
for(int i=0;i<n;i++){
if(hh<=tt&&q[hh]<=i-m) hh++;
while(hh<=tt&&a[q[tt]]>=a[i]) tt--;
q[++tt]=i;
if(i>=m-1) printf("%d ",a[q[hh]]);
}
cout<<endl;
hh=0,tt=-1;
for(int i=0;i<n;i++){
if(hh<=tt&&q[hh]<=i-m) hh++;
while(hh<=tt&&a[q[tt]]<=a[i]) tt--;
q[++tt]=i;
if(i>=m-1) printf("%d ",a[q[hh]]);
}
return 0;
}
multiset代码
因为元素有重复值,每次只删除重复值中的一个,那么要根据地址删。
#include<algorithm>
#include<set>
#include <iostream>
#include<cstring>
#include<vector>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
multiset<int> s;
int a[maxn];
vector<int> ans,ans2;
int main(){
int n,k;
cin>>n>>k;
for(int i=0;i<n;i++){
scanf("%d",a+i);
}
for(int i=0;i<k-1;i++) s.insert(a[i]);
for(int i=k-1;i<n;i++){
s.insert(a[i]);
ans.push_back(*s.begin());
ans2.push_back(*s.rbegin());
s.erase(s.find(a[i-k+1]));
}
for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
cout<<endl;
for(int i=0;i<ans2.size();i++) printf("%d ",ans2[i]);
cout<<endl;
return 0;
}