单调队列
单调队列——一种神奇的数据结构,顾名思义,指队列中的元素遵循单调递增(递减)的原则。队首元素保证是所求区间的最小(最大)值。
由于每个元素最多进队和出队一次,因此在求解问题时可以保证时间复杂度为 O(N)
用法说明
一般来说单调队列能够极大的优化时间,但是,具体而言适用范围有限,极少能够用到。单调递增队列可以理解为维护目标区间内最小值,单调递减区间为维护目标区间内最大值;其中,目标区间分固定和可变两种,根据具体要求调整维护策略很容易实现。
维护单调递增(递减)队列的步骤(用STL的deque实现):
- 如果队列的长度一定,先行判断队首元素是否在当前目标区间内,若超出范围则不断抛出队首元素;
- 在每次加入元素时,判断队列是否非空且当前元素小于(大于)队尾元素,若是则不断抛出队尾元素;直到队列为空或当前元素大于(小于)队尾元素,在队尾压入当前元素。
示例
根据下述例子给出示例代码:
假设共N=10个元素的数列8, 7, 12, 5, 16, 9, 17, 2, 4, 6.
求区间 [i,min(i+2, 9)](0≤i≤9) ,这10个区间的最大值。
#include<queue> //...省略部分必要头文件
using namespace std;
int arr[10] = {8, 7, 12, 5, 16, 9, 17, 2, 4, 6};
int seq_min[10];
void solve()
{
deque<pair<int,int> > que; //求固定区间最大值 —— 作单调递减队列
for(int i=0;i<=9;i++)
{
//步骤1 —— 判断队首元素是否在目标区间内,此次根据区间长度判断,固定区间长度为3
while(!que.empty() && que.front().second + 3 < i)
que.pop_front();
//步骤2 —— 当前元素与队尾元素大小比较
while(!que.empty() && que.back().first <= arr[i])
que.pop_back();
//队尾压入当前元素; pair<int,int> 为一个二元组,.first记录元素值,.second记录元素编号(用于处理区间长度判断)
que.push_back(make_pair(arr[i], i));
seq_min[i] = que.front().first;
}
}