单调队列,即内部元素相对于比较器有序的队列,可以方便的查询序列中某个连续区间内的最大/最小值
也能在状态转移时优化决策以降低时间复杂度。(嗯,这句是OI-Wiki上说的,作为蒟蒻qwq我并不知道如何优化dp)
比如我们想知道一个长为n的数字序列中每连续k个数中最小的那个数
如果暴力求解的话,遍历从1~n-k+1,复杂度O(n*k),而且需要将每个子序列中的值与其他值进行比较,是比较慢的=-=
对于这个问题就可以维护一个递减的单调队列,同时注意队列中的数字区间不要超过k
维护的方法:
每读入序列中的一个新的数,比较该数与队尾的数的关系
1.若该数大于队尾的数,入队。
2.若概述小于队尾的数,队尾的数出队,再次将该数与队尾的数进行比较。
入队后检查当前队首和队尾两个数所包含的数字区间是否超过k
如果超过则队首出队。
cin>>t; while(!dq.empty() && dq.back() > t) dq.pop_back(), no.pop_back(); dq.push_back(t), no.push_back(i); while(no.back() - no.front() >= k) dq.pop_front(), no.pop_front();
//这里是用deque做容器维护单调队列, no也是一个deque,维护在dq中数字的相应编号(下标)
这样维护的队列的队首元素总是每k个元素中最小的
O(1)即可取出,而每个数最多出队一次入队一次,维护队列的时间复杂度仅为O(n)
原文地址:https://www.cnblogs.com/leafsblogowo/p/12687225.html
时间: 2024-10-14 13:47:27