單調隊列經典題之一。
【思路】
設置兩個單調隊列分別記錄最大值和最小值。對於每一個新讀入的數字,進行兩次操作(對於求最大值和最小值中的某一個而言),一是若隊首不在滑窗范圍內則刪去;二是刪去隊末比當前值小(或大)的值,並將當前值插入對尾。每一次的最小(大)值就是當前單調隊列的隊首。
【錯誤點】
一定要寫while (scanf("%d%d",&n,&k)!=EOF),否則會WA。
我一開始的做法是這樣的:先把第一個數插入隊尾,再從第二個數開始進行后續操作。這樣的問題在於如果滑窗大小為1,則第一個數無法被輸出就出隊,導致WA。故一定要先設置一個空隊列,再逐一插入。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int MAXN=1000000+10; 5 int n,k,maxh,minh,maxt,mint; 6 int maxq[MAXN],minq[MAXN],num[MAXN]; 7 int maxans[MAXN],minans[MAXN]; 8 9 int main() 10 { 11 while (scanf("%d%d",&n,&k)!=EOF) 12 { 13 int maxhead=0,minhead=0,maxtail=0,mintail=0; 14 for (int i=0;i<n;i++) 15 { 16 /*刪除下標超出范圍的隊首元素*/ 17 if (maxhead<maxtail && maxq[maxhead]<=i-k) maxhead++; 18 if (minhead<mintail && minq[minhead]<=i-k) minhead++; 19 20 21 /*刪除隊尾元素*/ 22 scanf("%d",&num[i]); 23 while (maxhead<maxtail && num[maxq[maxtail-1]]<=num[i]) maxtail--;maxtail++; 24 maxq[maxtail-1]=i; 25 while (minhead<mintail && num[minq[mintail-1]]>=num[i]) mintail--;mintail++; 26 minq[mintail-1]=i; 27 maxans[i]=num[maxq[maxhead]]; 28 minans[i]=num[minq[minhead]]; 29 } 30 for (int i=k-1;i<n;i++) cout<<minans[i]<<' ';cout<<endl; 31 for (int i=k-1;i<n;i++) cout<<maxans[i]<<' ';cout<<endl; 32 } 33 return 0; 34 }