标签:单调队列
1.题目描述:点击打开链接
2.解题思路:本题利用单调队列解决。单调队列和单调栈性质一样,内部元素严格单调递增排列。单调队列的一个典型应用就是本题的求滑动窗口的最值问题。那么怎么求解呢?首先,由于长度为k,因此我们可以先把0到k-1的下标全部试图入队列。在加入元素i时,若队列的末尾的值j满足Aj≥Ai,则不断地取出,直到队列为空或者Aj<Ai之后再在末尾加入i。此时,如果k-1也加入到了队列时,查看队列头部的值j,那么B0=Aj。如果队列头部元素==i-k+1,那么这个元素以后肯定用不到了,删去。这样就求出了最小值。用同样类似的写法可以求出最大值。
还可以简单的理解:从头滑到尾可以求出最小值,从尾滑到头可以求出最大值。
3.代码:
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> #include<cassert> #include<string> #include<sstream> #include<set> #include<vector> #include<stack> #include<map> #include<queue> #include<deque> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<cctype> #include<functional> using namespace std; #define me(s) memset(s,0,sizeof(s)) typedef long long ll; typedef unsigned int uint; typedef unsigned long long ull; typedef pair <int, int> P; const int N=1000000+10; int n,k; int a[N]; int b[N]; int c[N]; int deq[N]; int main() { while(~scanf("%d%d",&n,&k)&&(n||k)) { for(int i=0;i<n;i++) scanf("%d",&a[i]); int s=0,t=0; //求最小值 for(int i=0;i<n;i++) { while(s<t&&a[deq[t-1]]>=a[i])t--; //不满足严格单调递增性,不断地取出 deq[t++]=i; //从尾部入队列 if(i-k+1>=0)b[i-k+1]=a[deq[s]]; //如果滑动窗口起点变为非负数,那么最小值就是a[deq[s]] if(deq[s]==i-k+1)s++; //说明滑动窗口的起点和队首相同,以后的滑动窗口肯定用不到队首元素了,删去 } s=t=n; //用同样的方法求最大值,只不过要逆序 for(int i=n-1;i>=0;i--) { while(s<t&&a[i]>=a[deq[s]])s++; deq[--s]=i; //从头部插入元素 if(i+k-1<n)c[i]=a[deq[t-1]]; //如果滑动窗口的终点<n,那么最大值等于a[deq[t-1]] if(deq[t-1]==i+k-1)t--; //如果滑动窗口的终点和队尾相同,以后的滑动窗口肯定用不到队尾了,删去 } for(int i=0;i<=n-k;i++) printf("%d%c",b[i]," \n"[i==n-k]); for(int i=0;i<=n-k;i++) printf("%d%c",c[i]," \n"[i==n-k]); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:单调队列
原文地址:http://blog.csdn.net/u014800748/article/details/47701699