B - Sliding Window 单调队列
题意
给你一串长为n的序列,给你一个整数k代表窗口的长度为k,从序列左端到右端,你需要找到每个连续的长度为k的区间的最小值和最大值
思路
如果暴力来做,遍历n次k个数,那就是n方的复杂度;如果维护一个线段树那就是nlogn,每个数只被插入一次和删除一次。
我们可以维护两个单调队列,单调递增队列用于计算窗口的最小值,每删去一个数就看队头有没有出去,出去就出队,新增一个数就和队尾比较,直到能放下去,维护n次,每次的队头就是区间的最小值,最大值同理,复杂度为n。
AC代码
#include<iostream> #include<stdio.h> using namespace std; const int maxn=1e6+5; int a[maxn],que[maxn],label[maxn]; int n,k,head,tail; int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); head=1;tail=0; for(int i=1;i<=n;i++){ while(head<=tail&&i-label[head]>=k) head++; while(head<=tail&&que[tail]>=a[i]) tail--; que[++tail]=a[i]; label[tail]=i; if(i>=k) printf("%d ",que[head]); } printf("\n"); head=1;tail=0; for(int i=1;i<=n;i++){ while(head<=tail&&i-label[head]>=k) head++; while(head<=tail&&que[tail]<=a[i]) tail--; que[++tail]=a[i]; label[tail]=i; if(i>=k) printf("%d ",que[head]); } return 0; }
一点一点积累,一点一点蜕变!