POJ 2823 - Sliding Window(单调队列)

题目链接 https://cn.vjudge.net/problem/POJ-2823

【题意】
给你一个长度为n的序列a[1],a[2]…a[n]和一个整数k,求数列bi=min{a[i],a[i+1],…a[i+k-1]},和数列ci=max{a[i],a[i+1],…a[i+k-1]},i=1,2,…n-k+1(1<=k<=n<=1e6,0<=a[i]<=1e9)

【思路】
单调队列的模板题,单调队列最基础的应用就是处理滑动窗口的最值问题,可以用双端队列deque实现,把这道题当作模板记录下来,时间复杂度为O(n)

#include<cstdio>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;

const int maxn=1000050;

int n,k;//序列长度,窗口大小
int a[maxn];
deque<int> minq,maxq;//最小值,最大值的单调队列
int Max[maxn],Min[maxn];

void getMin(){//计算最小值
	minq.clear();
	for(int i=1;i<k;++i){
		while(minq.size() && a[minq.back()]>=a[i]) minq.pop_back();
		minq.push_back(i);
	}
	for(int i=1;i<=n-k+1;++i){
		int j=i+k-1;
		while(minq.size() && minq.front()<i) minq.pop_front();
		while(minq.size() && a[minq.back()]>=a[j]) minq.pop_back();
		minq.push_back(j);
		Min[i]=a[minq.front()];
	}
}

void getMax(){//计算最大值
	maxq.clear();
	for(int i=1;i<k;++i){
		while(maxq.size() && a[maxq.back()]<=a[i]) maxq.pop_back();
		maxq.push_back(i);
	}
	for(int i=1;i<=n-k+1;++i){
		int j=i+k-1;
		while(maxq.size() && maxq.front()<i) maxq.pop_front();
		while(maxq.size() && a[maxq.back()]<=a[j]) maxq.pop_back();
		maxq.push_back(j);
		Max[i]=a[maxq.front()];
	}
}

int main(){
	while(scanf("%d%d",&n,&k)==2){
		for(int i=1;i<=n;++i) scanf("%d",&a[i]);
		getMin();
		getMax();
		for(int i=1;i<=n-k+1;++i){
			printf("%d%c",Min[i],i==n-k+1?'\n':' ');
		}
		for(int i=1;i<=n-k+1;++i){
			printf("%d%c",Max[i],i==n-k+1?'\n':' ');
		}
	}
	return 0;
}

用数组模拟双端队列会更快

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxn=1000005;

int n,k;
int a[maxn];
int q[maxn],s,t;
int Min[maxn],Max[maxn];

void getMin(){
	s=t=0;
	for(int i=1;i<=k-1;++i){
		while(s<t && a[q[t-1]]>=a[i]) --t;
		q[t++]=i;
	}
	for(int j=k;j<=n;++j){
		int i=j-k+1;
		while(s<t && q[s]<i) ++s;
		while(s<t && a[q[t-1]]>=a[j]) --t;
		q[t++]=j;
		Min[i]=a[q[s]];
	}
} 

void getMax(){
	s=t=0;
	for(int i=1;i<=k-1;++i){
		while(s<t && a[q[t-1]]<=a[i]) --t;
		q[t++]=i;
	}
	for(int j=k;j<=n;++j){
		int i=j-k+1;
		while(s<t && q[s]<i) ++s;
		while(s<t && a[q[t-1]]<=a[j]) --t;
		q[t++]=j;
		Max[i]=a[q[s]];
	}
}

int main(){
	while(scanf("%d%d",&n,&k)==2){
		for(int i=1;i<=n;++i) scanf("%d",&a[i]);
		getMin();
		getMax();
		for(int i=1;i<=n-k+1;++i) printf("%d%c",Min[i],i==n-k+1?'\n':' ');
		for(int i=1;i<=n-k+1;++i) printf("%d%c",Max[i],i==n-k+1?'\n':' ');
	}
	return 0;
}
posted @ 2018-07-31 22:55  不想吃WA的咸鱼  阅读(101)  评论(0编辑  收藏  举报