给定一个长度为N的序列,以及一个整数K,要求找出该序列所有长度为K的子段里面元素的最大值和最小值。
比如序列为(1, 3, -1, -3, 5, 3, 6, 7),K = 3(1,3,−1,−3,5,3,6,7),K=3, 那么其各个子段的位置,以及最大值,最小值如下表所示。
输入
第一行两个整数$ N,K (1 \le K \le N \le 10^6 )。
第二行有N个整数,表示序列。序列中的元素绝对值不超过10^9109。
输出
第一行输出每个子段的最小值,按照子段从左到右的顺序输出。
第二行输出每个子段的最大值,按照子段从左到右的顺序输出。
样例
输入
复制
8 3 1 3 -1 -3 5 3 6 7
输出
复制
-1 -3 -3 -3 3 3 3 3 5 5 6 7
单调队列: 下标递增,值维护为单调的。
应用:通常用o(n)的时间复杂度求定长区间的最值。
列如:
v:1 3 -1 -3 5 3 6 7 k=3 维护一个递增的单调队列
(1)当前判断元素 (1,1)(下标,值)
单调队列 元素 (1,1)
(2)当前判断元素 (2,3)(下标,值)
单调队列 元素 (1,1)(2,3)
(3)当前判断元素 (3,-1)(下标,值)
因为-1比队列里的值都要小,队列里的值出队列。
单调队列 元素 (1,1)(2,3)(3,-1) 输出最小值 -1
(4)当前判断元素 (4,-3)(下标,值)
单调队列 元素 (3,-1), (4,-3) 输出最小值 -3
(5)当前判断元素 (5,5)(下标,值)
单调队列 元素 (4,-3)(5,5) 输出最小值 -3
(6)当前判断元素 (6,3)
单调队列 元素 (4,-3)(5,5) (6,3) 输出最小值 -3
(7)当前判断元素 (7,6)
单调队列 元素 (4,-3)[7-4=3,区间长度大于3删掉] ,(6,3) (7,6) 输出最小值 3
(8)当前判断元素 (8,7)
单调队列 元素 (6,3),(7,,6) 输出最小值3
#include <iostream>
#include<vector>
#define MA 1000020
using namespace std;
int q[MA],st,ed,n,k;
bool empty(){
return st==ed;
}
void clear(){
st=ed=0;
}
int main()
{
while(cin>>n>>k&&n&&k){
vector<int> v(n+1);
for(int i=1;i<=n; i++){
cin>>v[i];
}
clear();
for(int i=1; i<=n;i++){
while(!empty()&& v[i]<=v[q[ed-1]]){//假如进队列的数比前一个进队列的数还要小,则删掉前一个数,因为找到了更小的值,删掉的数没有了贡献。
ed--;
}
q[ed++]=i;
while(!empty()&&i-q[st]>=k){//假如区间长度>k且队列不为空,把队首元素删掉
st++;
}
if(i>=k){
cout<<v[q[st]]<<" ";
}
}
cout<<endl;
clear();
for(int i=1; i<=n; i++){
while(!empty()&&v[i]>=v[q[ed-1]]){
ed--;
}
q[ed++]=i;
while(!empty()&&i-q[st]>=k){
st++;
}
if(i>=k){
cout<<v[q[st]]<<" ";
}
}
}
return 0;
}