数据结构1.2-单调队列
一、简述
本节介绍一下单调队列及其一些应用。
二、单调队列
单调队列就是队列元素满足单调性的一类数据结构,主要用于解决滑动窗口类的问题,即维护一个区间的最值,在应用时时间复杂度是
一般的,如果我们维护区间的最小值,那么维护的队列是单调递增的;如果是维护区间的最大值,那么队列是单调递减的。
三、例题
1.[AcWing154.滑动窗口]
题目描述
给定一个大小为
有一个大小为
你只能在窗口中看到
每次滑动窗口向右移动一个位置。
以下是一个例子:
该数组为 [1 3 -1 -3 5 3 6 7]
,
窗口位置 | 最大值 | 最小值 |
---|---|---|
[1 3 -1] -3 5 3 6 7 | 3 | -1 |
1 [3 -1 -3] 5 3 6 7 | 3 | -3 |
1 3 [-1 -3 5] 3 6 7 | 5 | -3 |
1 3 -1 [-3 5 3] 6 7 | 5 | -3 |
1 3 -1 -3 [5 3 6] 7 | 6 | 3 |
1 3 -1 -3 5 [3 6 7] | 7 | 3 |
你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。
输入格式
输入包含两行。
第一行包含两个整数
第二行有
同行数据之间用空格隔开。
输出格式
输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。
输入样例
8 3
1 3 -1 -3 5 3 6 7
输出样例
-1 -3 -3 -3 3 3
3 3 5 5 6 7
解题思路
这是单调队列的模板题。
以求最小值为例。我们用队列维护一个单调递增的队列。从前往后遍历序列,首先队列非空并且队尾元素大于等于当前元素,那么一直弹出队尾,为什么?因为我们要维护最小值,队列中的元素都在区间内,那么当前元素更小,那么队列中比它大的元素一定不会是二者所在区间的最小值,所以要弹出。然后将当前元素入队。如果说队头元素不在区间内了,那么队头要弹出。最后队头就是就是区间最小值。
最大值类似。
C++代码
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int n, k;
int q[N], a[N];
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
int hh = 0, tt = -1;
for (int i = 1; i <= n; i ++)
{
while (hh <= tt && a[q[tt]] >= a[i])
tt --;
q[++ tt] = i;
if (q[hh] + k - 1 < i)
hh ++;
if (i >= k) printf("%d ", a[q[hh]]);
}
printf("\n");
hh = 0, tt = -1;
for (int i = 1; i <= n; i ++)
{
while (hh <= tt && a[q[tt]] <= a[i])
tt --;
q[++ tt] = i;
if (q[hh] + k - 1 < i)
hh ++;
if (i >= k) printf("%d ", a[q[hh]]);
}
return 0;
}
2.[Daimayuan Online Judge.最大连续区间和]
题目描述
给你
请求出满足条件的最大连续区间和。
输入格式
第一行三个整数
接下来一行
输出格式
输出一行一个数,表示答案。
数据范围
对于
输入样例
6 2 3
-1 3 -3 4 -5 4
输出样例
4
解题思路
首先看到区间和,那么就要想到前缀和。我们固定
C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, l, r;
int a[N], s[N];
int q[N], hh = 0, tt = -1;
int main()
{
scanf("%d%d%d", &n, &l, &r);
for (int i = 1; i <= n; i ++)
{
scanf("%d", &a[i]);
s[i] = s[i - 1] + a[i];
}
int x = l, res = - (1 << 30);
for (int i = 1; i + l - 1 <= n; i ++)
{
while (x <= i + r - 1 && x <= n)
{
while (hh <= tt && s[q[tt]] <= s[x])
tt --;
q[++ tt] = x;
x ++;
}
if (q[hh] < i + l - 1)
hh ++;
res = max(res, s[q[hh]] - s[i - 1]);
}
printf("%d\n", res);
return 0;
}
3.[Daimayuan Online Judge.覆盖]
题目描述
在一张网格图中,每一列有且仅有一个格子被小蜗涂了色,第
现在有一块高度为
输入格式
第一行两个整数
接下来一行
输出格式
输出一行一个数,表示答案。
数据范围
对于
输入样例
7 4
1 4 5 3 6 1 4
输出样例
4
解题思路
我们维护一个区间,区间为
C++代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, h;
int a[N];
int q_max[N], q_min[N];
int hh_max, tt_max = -1;
int hh_min, tt_min = -1;
int main()
{
scanf("%d%d", &n, &h);
for (int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
int j = 0, ans = 0;
for (int i = 1; i <= n; i ++)
{
if (hh_max <= tt_max && q_max[hh_max] < i)
hh_max ++;
if (hh_min <= tt_min && q_min[hh_min] < i)
hh_min ++;
while (j <= n && (j <= i || a[q_max[hh_max]] - a[q_min[hh_min]] <= h))
{
j ++;
if (j > n)
break;
while (hh_max <= tt_max && a[q_max[tt_max]] <= a[j])
tt_max --;
q_max[++ tt_max] = j;
while (hh_min <= tt_min && a[q_min[tt_min]] >= a[j])
tt_min --;
q_min[++ tt_min] = j;
}
ans = max(ans, j - i);
}
printf("%d\n", ans);
return 0;
}
本文来自博客园,作者:Cocoicobird,转载请注明原文链接:https://www.cnblogs.com/Cocoicobird/p/17176639.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架