单调数据结构总结
单调数据结构是一种在我看来很神奇的数据结构,其中包括单调栈和单调队列,但其实它们的思想几乎是完全一致的,可以说单调队列就是单调栈的升级版本。
我们知道单调队列是可以由两端出队的,也就是双端队列 std::deque
;而单调栈就是普通的栈,但是 std::stack
的底层就是由 std::deque
来实现的,因此得出结论,单调队列就是单调栈的升级版本,因此,让我们先来讨论关于单调栈的事情。
1. 单调栈
单调栈的核心只有一句话:排除所有显然不可能的决策。
例题: 单调栈模板题目
题意:求一个序列中每个数右边第一个大于它的数。
我们建立一个栈,依次让每个数入栈。由于记录的是每一个数右边的第一个大于它的数字,因此需要采用倒序遍历每一个数。
单调栈的核心:当每一次要将一个数入栈时,显然,当前在栈内的元素全部在这个数的右端。考虑到我们只记录在它右边第一个大于它的数,因此不断循环判断栈顶元素,如果栈顶元素还没有当前所求的数大,显然它绝对不会成为答案,因此我们就可以将它直接弹出。显然地,当遇到栈顶元素已经大于当前判断的数了,又结合到我们的入栈次序使得栈里的元素的位置绝对递增,再向后遍历到的不会成为最优解,那当前的数显然就成为了第一个大于所判断的数字的数,记录答案。
形象地描绘步骤:
记当前遍历到的数是
下来给出参考程序
#include<stdio.h>
#define maxn 100005
int stk[maxn], a[maxn];
int ans[maxn];
int n, top;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
stk[++top] = n + 1;//要先压入一个元素,防止爆栈
for(int i = n; i; i--){//倒序遍历
while(top && a[stk[top]] <= a[i])//栈中还有元素并且栈顶元素不大于当前元素
top--;//出栈
if(top)//如果栈里还有元素
ans[i] = stk[top];//记录答案;由于一开始就是倒序遍历,因此越左边的数越晚入栈,因此栈顶就是答案
stk[++top] = i; //将当前元素入栈
}
for(int i = 1; i <= n; i++)
printf("%d\n", ans[i]);//输出
return 0;
}
分析时间复杂度:
最外层的遍历是
2. 单调队列
单调队列其实就是单调栈的升级版本。回顾单调栈的例题,我们所求的是每个数在序列当中在它右边最大的数,单调队列不过是添加了一个限制——所求的答案和原数距离不超过k。因此单调队列的思想便显然了——在遍历出队之后检查队首与队尾的距离,超过则从队首出队即可。其它在单调栈的基础上不需要做任何改动。
上代码——
int head = 1, tail = 0;
for(int i = 1; i <= n; i++){
while(head <= tail && a[q[tail]] > a[i])
tail--;//这一步是不满足可行性时的出队
while(head <= tail && q[head] + k <= i)//相对于单调栈只多了这一步
head++;//这一步是不满足距离要求的出队
q[++tail] = i;//这一步是遍历时的入队
ans[i] = q[head];
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探