题解:来自http://hi.baidu.com/wzyjerry/blog/item/3838f48af40e40cafd1f1089.html
题目大意:给你一个长度为n的数组,求从左到右的每个相邻的长度为k的区间内数的最大值和最小值。
解题方法:这道题数据较大(n最大为10^6)所以用纯模拟O(n*k)是铁定挂掉的,写的好的线段树可以卡时间过去。这里我们选择更为合适的单调队列解决。STL里有类似的优先队列。单调队列就是在一个队列中保证数据的单调性,可以很方便的求制定区间极值的一种队列。每个元素只会进队一次,所以复杂度为O(n),可以有效地降低时间复杂度。下面具体地说明一下单调队列。
1.数据结构:理论上来说应当是两个数组,一个存元素,一个存这个元素在原队列中的下标。实际上如果保留原队列的话,只需要记录下标即可。这样简化为只开一个长度为n的数组Q,减少了一半的空间开销。另外要记录队首s和队尾t。
2.初始化:将队首赋值为第一个元素。
3.维护过程(这里以建立单增队列求最大值为例):依次枚举剩下的N-1个元素,并且将当前未入队的第一个元素和队尾元素比较,当且仅当队列为非空并且队尾元素的值小于当前未入队的元素时,将队尾元素删除(也就是队尾指针-1),因为当前的元素比队尾元素大,所以在区间内队尾元素不会是最大值了。重复这个过程直到队列空或者队尾元素比当前元素大,一次插入结束。
题目大意:给你一个长度为n的数组,求从左到右的每个相邻的长度为k的区间内数的最大值和最小值。
解题方法:这道题数据较大(n最大为10^6)所以用纯模拟O(n*k)是铁定挂掉的,写的好的线段树可以卡时间过去。这里我们选择更为合适的单调队列解决。STL里有类似的优先队列。单调队列就是在一个队列中保证数据的单调性,可以很方便的求制定区间极值的一种队列。每个元素只会进队一次,所以复杂度为O(n),可以有效地降低时间复杂度。下面具体地说明一下单调队列。
1.数据结构:理论上来说应当是两个数组,一个存元素,一个存这个元素在原队列中的下标。实际上如果保留原队列的话,只需要记录下标即可。这样简化为只开一个长度为n的数组Q,减少了一半的空间开销。另外要记录队首s和队尾t。
2.初始化:将队首赋值为第一个元素。
3.维护过程(这里以建立单增队列求最大值为例):依次枚举剩下的N-1个元素,并且将当前未入队的第一个元素和队尾元素比较,当且仅当队列为非空并且队尾元素的值小于当前未入队的元素时,将队尾元素删除(也就是队尾指针-1),因为当前的元素比队尾元素大,所以在区间内队尾元素不会是最大值了。重复这个过程直到队列空或者队尾元素比当前元素大,一次插入结束。
4.由于单调队列是求指定长度区间的最值,所以需要控制区间长度。当插入结束后,需要用队尾元素下标和队首元素下标计算是否在一个区间内。如果不在,队首元素出队(队首指针+1)。重复这个过程直到控制到区间内,一次最大值寻找完毕。最大值出现在队首。
补充:本题输出输出量巨大,需要使用输入输出外挂,并且是能处理负数的。
/*
ID: sdj22251
PROG: subset
LANG: C++
*/
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#define LOCA
#define MAXN 1005*1005
#define INF 100000000
#define eps 1e-7
using namespace std;
int a[MAXN];
int q[MAXN];
int in()
{
int flag = 1;
char ch;
int a = 0;
while((ch = getchar()) == ' ' || ch == '\n');
if(ch == '-') flag = -1;
else
a += ch - '0';
while((ch = getchar()) != ' ' && ch != '\n')
{
a *= 10;
a += ch - '0';
}
return flag * a;
}
void out(int a)
{
if(a < 0) {putchar('-'); a = -a;}
if(a >= 10)out(a / 10);
putchar(a % 10 + '0');
}
int main()
{
int n, k;
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i++)
a[i] = in();
int head = 0, tail = 0;
q[++tail] = 1;
for(int i = 1; i <= n; i++)
{
while(head <= tail && a[q[tail]] >= a[i])
tail--;
q[++tail] = i;
while(q[tail] - q[head] + 1 > k)
head++;
if(i == k)
out(a[q[head]]);
else if(i > k)
{
putchar(' ');
out(a[q[head]]);
}
}
putchar('\n');
head = 0, tail = 0;
q[++tail] = 1;
for(int i = 1; i <= n; i++)
{
while(head <= tail && a[q[tail]] <= a[i])
tail--;
q[++tail] = i;
while(q[tail] - q[head] + 1 > k)
head++;
if(i == k)
out(a[q[head]]);
else if(i > k)
{
putchar(' ');
out(a[q[head]]);
}
}
putchar('\n');
return 0;
}
本文介绍了一种使用单调队列解决给定数组中从左到右每相邻长度为k的区间内数的最大值和最小值的问题。通过优化数据结构,将复杂度降低到O(n),有效提升了算法效率。
257

被折叠的 条评论
为什么被折叠?



