单调队列 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;
}
初谈这个话题,相信许多人会有一种似有所悟,但又不敢确定的感觉。没错,这正是因为其中“单调”一词的存在,所谓单调是什么,学过函数的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;
}
相关文章推荐
- poj2823(单调队列)
- POJ2823--Sliding Window(单调队列)
- poj2823_单调队列简单入门
- POJ2823 Sliding Window(单调队列)
- ACM-单调队列之Sliding Window——poj2823
- POJ2823 滑动窗口 单调队列模板题 第一次用了发函数指针
- POJ2823 单调队列
- poj2823-单调队列
- POJ2823 Sliding Window(单调队列)
- 单调队列 poj2823 Sliding Window
- Poj2823 Sliding Window (单调队列)
- poj2823 Sliding Window(单调队列)
- 单调队列--poj2823 Sliding Window
- POJ2823 Sliding Window(单调队列模版题)
- poj2823单调队列(模拟优先队列)
- poj2823 单调队列以及双端队列(deque)
- [poj2823]sliding windows(单调队列模板题)
- POJ2823(单调队列初步)
- poj2823(单调队列)
- 单调队列-poj2823