您的位置:首页 > 其它

单调队列 poj2823

2016-10-31 17:37 176 查看
这段话转自:http://www.cnblogs.com/szy-wlxy/p/4622662.html

        初谈这个话题,相信许多人会有一种似有所悟,但又不敢确定的感觉。没错,这正是因为其中“单调”一词的存在,所谓单调是什么,学过函数的people都知道单调函数或者函数的单调性,直白一点说单调就是一直增或一直减。例如:1,3,5,9就是一个单调增数列,数列中不存在后一个数比前一个数小的现象。那么同样,在这里谈到的话题也有类似特点。

       先说一下单调队列吧! 单调队列,就是一个符合单调性质的队列,它同时具有单调的性质以及队列的性质。他在编程中使用频率不高,但却占有至关重要的地位。它的作用很简单,就是为了维护一组单调数据,让我们在运行的过程中能够快速寻求前k个或后k个中最大或最小的值。    至于单调栈,相信看完上面的叙述后,都会有一个大概的理解,单调栈就是一个符合单调性质的栈它同时具有单调的性质以及栈的性质。在作用方面两者是相同的,差别仅是在编程过程中所维护的数组的方式不同。

       下面我会举个简单的列子来解释单调队列及单调栈。

       例题:有一组数据1,5,9,4,7,8,6,他们会依此输入,同时,在某一时刻会让你求出后n个数中的最大值。                 

       根据题意,我们可以得出这样一个结论,若后一个数大于前一个数,则结果必定不会是前一个数(比如现在输入了1,5,由于1<5,所以无论是后几个数中的最大值均不会为1),因此,我们只需维护一个单调递减的数组便可快速求得所需值。(数组变化如下:输入——1,数组——1;输入——5,由于5>1删去1添入5,数组——5;输入——9,由于9>5删去5添入9,数组——9;输入——4,由于4<9直接添入,数组——9,4;输入——7,由于7>4同时7<9因此删去4添入7,数组——9,7;输入——8,由于8>4同时8<9因此删去7添入8,数组——9,8;输入——6,由于6<8直接添入,数组——9,8,6。)总的来说,它的本质就是当你在插入一个值时,应将在他之前存入的所有小于他的数值剔除,再将他存入数组中。

本人的理解:

假设需要寻找移动窗口中的最小值,如果这时候数据中进入了一个比队列末尾的值还要小的元素,由于这个值的位置(数据流中的位置)靠后,而且比队列中的最后一个元素还要小,那么队列中的最后一个元素就没有存在的必要了(因为这时候的窗口中无论如何都选不到它),之后在和队列中的前一个元素相比,直到遇到比它还小的值,这时候把这个元素插入。(注意:队列中的每个元素需要保存两个信息:一个是元素的值,另一个是元素在数据流中的位置,位置信息是用来判断是否该元素已经离开窗口范围)。

//代码压着时间过了,应该还有需要优化的地方
#include <iostream>
#include <queue>
#include <stdio.h>
#include <stdlib.h>

using namespace std;
const int maxn = 1e+6 + 100;
typedef pair<int, int> node;

deque<node> maxque, minque;
int n, k, num[maxn];

void workMax()
{
maxque.push_back(node(0, num[0]));
for (int i = 1; i < k; i++)
{
while (!maxque.empty() && num[i] >= maxque.back().second)
maxque.pop_back();
maxque.push_back(node(i, num[i]));
}

printf("%d", maxque.front().second);
for (int i = k; i < n; i++)
{
while (!maxque.empty() && num[i] >= maxque.back().second)
maxque.pop_back();
maxque.push_back(node(i, num[i]));
if (maxque.front().first < i - k + 1)
maxque.pop_front();
printf(" %d", maxque.front().second);
}
}

void workMin()
{
minque.push_back(node(0, num[0]));
for (int i = 1; i < k; i++)
{
while (!minque.empty() && num[i] <= minque.back().second)
minque.pop_back();
minque.push_back(node(i, num[i]));
}

printf("%d", minque.front().second);
for (int i = k; i < n; i++)
{
while (!minque.empty() && num[i] <= minque.back().second)
minque.pop_back();
minque.push_back(node(i, num[i]));
if (minque.front().first < i - k + 1)
minque.pop_front();
printf(" %d", minque.front().second);
}
}

int main()
{
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i++)
scanf("%d", &num[i]);
workMin();
printf("\n");
workMax();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 队列