Zskioaert1106
2024-11-09 14:16:36
单调队列是一种快速查找滑动窗口内最值的方法,其时间复杂度竟可以达到
其方法是维护一个队列
每次将滑动窗口最右端的元素
然后如果队头的下标不在滑动窗口的范围内就将其AFO删除。最后每次的队头即滑动窗口内的最值。
下面是正确性的证明:
对队头的处理使得队列
队尾处清除的元素都是在现在及未来的滑动窗口中不再会成为选择的,因为滑动窗口是右移的,所以新的
留下的元素都是还有可能成为选择的,并且越靠前的元素越大,所以队头一定是当前的最优结果。
由于每个元素只会入队、出队一次,所以时间复杂度是
通常来讲,单调队列需要存下来数列
下面是一个求长度为
#include<iostream>
int n,k,a[MAXN],q[MAXN],front=1,tail;
int main(){
std::cin>>n>>k;
for(int i=1;i<=n;i++){
std::cin>>a[i];
while(front<=tail/*队列不为空*/ && a[q[tail]]<=a[i]/*队尾不比新元素更优*/)
tail--;
q[++tail]=i;//将最新元素入队
if(i-q[front]>=k)//清除非法队头
front++;
if(i>=k)//输出
std::cout<<"左端为"<<i-k+1<<"、右端为"<<i<<"的滑动窗口中最大值为"<<a[q[front]]<<";\n";
}
return 0;
}
注意到清除队头处用的不是 while
而是 if
,这是因为该滑动窗口每次右移
不仅最大,单调队列适用于求各种最值,其本质是一样的。你可以做这几道题以练习单调队列的写法:
注意单调队列的题目并不都是这么板,比如不连续下标还需要排序的滑动窗口:
单调队列通常不是直接作为考点出现在题目中,而是用以优化动态规划或其它算法。
这道题可以用前缀和做,即求最大的
这道题是明鲜的动态规划,先把转移方程列出来:
当然这样你就会被 hack,所以要注意
思考:这道题很像上面两道题的结合版,应该怎么把两道的思路结合起来?