网上很多讲单调队列的资料,但是感觉讲的不是很清楚,大多都是只讲了思路,没有用实际的例子来阐述单调队列。
单调队列,顾名思义是指队列内的元素是有序的,队头为当前的最大值(单调递减队列)或最小值(单调递增序列),以单调递减队列为例来看队列的入队和出队操作:
1、入队:
如果当前元素要进队,把当前元素和队尾元素比较,如果当前元素小于队尾元素,那么当前元素直接进队,如果当前元素大于队尾元素,那么队尾出队,将当前元素和新的队尾再做比较,直到当前元素大于队尾元素或者队列为空。单调队列只能在队尾插入元素,队尾和队头都可以删除元素。
2、出队:
出队直接取队头即可,因为用单调队列就是为了取最值,而队头就是最值。
例子:将数组a[] = {3, 5, 2, 8, 1, 4, 7}依次入队,并保证队列为一个单调递减队列。
#include
#include
#include
#include
using namespace std;
vector WinMax(vector& ivec, int k)
{
assert(!ivec.empty());
int size = ivec.size();
vector res(size + k - 1);
deque que;
//首先将下标0入队
que.push_back(0);
res[0] = ivec[que.front()];
for (int i = 1; i < size; ++i)
{
//如果当前下标超出范围就删除队头
if (que.front() < i - k + 1)
que.pop_front();
//将当前元素入队
while (!que.empty())
{
if (ivec[i] > ivec[que.back()])
que.pop_back();
else
break;
}
que.push_back(i);
res[i] = ivec[que.front()];
}
//当窗口右端超出数组范围,进行特殊处理
for (int i = size; i < size + k - 1; ++i)
{
if (que.front() < i - k + 1)
que.pop_front();
res[i] = ivec[que.front()];
}
return res;
}
void main()
{
int a[] = {7, 3, 2, 5, 6};
vector ivec(a, a + 5);
vector res = WinMax(ivec, 3);
for (int i = 0; i < res.size(); ++i)
cout << res[i] << endl;
}
#include
#include
#include
#include
using namespace std;
vector RightMin(vector& ivec)
{
assert(!ivec.empty());
int size = ivec.size();
vector res(size);
deque que;
//先将下标0入队
que.push_back(0);
for (int i = 1; i < size; ++i)
{
while (!que.empty())
{
//如果当前元素大于队尾,直接入队
if (ivec[i] >= ivec[que.back()])
{
que.push_back(i);
break;
}
//否则就出队,并将对应的值保存
else
{
res[que.back()] = ivec[i - 1];
que.pop_back();
}
}
if (que.empty())
que.push_back(i);
}
//当元素遍历完之后,将队列的所有元素出队,并保存对应的值
while (!que.empty())
{
res[que.back()] = ivec[size - 1];
que.pop_back();
}
return res;
}
void main()
{
int a[] = {3, 5, 4, 7, 1, 6, 2};
vector ivec(a, a + 7);
vector res = RightMin(ivec);
for (int i = 0; i < res.size(); ++i)
cout << res[i] << endl;
}