单调栈 && 单调队列
单调栈
适用于求左边或者右边离它最近的(比它大或者小)的数
1>【模板】单调栈
题目描述
给出项数为
定义函数
试求出
输入格式
第一行一个正整数
第二行
输出格式
一行
样例
5 1 4 2 3 5
2 5 4 5 0
提示
对于
思路
设当前数为a 2
a 2 之后第一个比a 2 大的数
栈顶元素
刚好满足这一要求,如果该栈是单调递减的
由于要输出下标,所以就将下标存入栈中
代码
#include <iostream> #include <stack> #include <vector> using namespace std; const int N = 3e6 + 10; stack<int> a; int b[N]; vector<int> c; int main() { int n; cin >> n; for(int i = 1; i <= n; i++) cin >> b[i]; for(int i = n; i > 0; i--) //起到反转的效果 { while(!a.empty() && b[a.top()] <= b[i]) a.pop(); //不符合单调递减的条件就会一直出栈 c.push_back(a.empty() ? 0 : a.top()); //若栈为空,则没有元素比它大;若非空,则栈顶元素就是第一个大于它的 a.push(i); } for(int i = c.size() - 1; i >= 0; i--) cout << c[i] << ' '; }
2>求数列所有后缀最大值的位置
题目描述
给定一个数列
每次操作结束后,请你找到当前
为了避免输出过大,请你每次操作结束后都输出一个整数,表示当前数列所有后缀最大值
的下标的按位异或和
。
输入格式
第一行是一个整数,表示操作次数
第二行有
输出格式
每次操作后请输出一行一个整数,表示当前数列所有后缀最大值下标的按位异或和。
样例
5 2 1 3 5 4
1 3 3 4 1
提示
对于全部的测试点,保证
思路
后缀最大值 单调递减栈的栈底元素
代码
#include <iostream> #include <stack> using namespace std; typedef unsigned long long llu; const int N = 1e6 + 10; stack<llu> a; llu b[N], count; int main() { llu n; scanf("%llu", &n); for(llu i = 1; i <= n; i++) { scanf("%llu", &b[i]); while(!a.empty() && b[a.top()] <= b[i]) count ^= a.top(), a.pop(); count ^= i, a.push(i); printf("%llu\n", count); } }
单调队列
适用于求区间最值
, 队列头就是最值
思考步骤
- 判断是否需要弹出队尾(直至满足单调性)
- 插入元素 <若在最后才插入元素,当队列为空的情况可能会随机输出一个数>
- 判断队头是否要出队(区间长度超过特定值)
- 只有至少构成了一个窗口,才能输出队头
代码
#include <iostream> #include <deque> using namespace std; const int N = 1e6 + 10; deque<int> a; //存数字 int b[N]; int main() { int n, k; cin >> n >> k; for(int i = 0; i < n; i++) cin >> b[i]; //min for(int i = 0; i < n; i++) { //判断队尾元素是否要出队 while(a.size() && a.back() > b[i]) a.pop_back(); //新元素入队 a.push_back(b[i]); //判断队头元素是否要出队(队伍长度是否大于k) if(i - k >= 0 && b[i - k] == a.front()) a.pop_front(); //构成了一个区间,则输出队头元素,队头就是最值 if(i + 1 >= k) cout << a.front() << ' '; } cout << endl; a.clear(); //记得清空 //max for(int i = 0; i < n; i++) { while(a.size() && a.back() < b[i]) a.pop_back(); a.push_back(b[i]); if(i - k >= 0 && b[i - k] == a.front()) a.pop_front(); if(i + 1 >= k) cout << a.front() << ' '; } }
#include <iostream> #include <deque> using namespace std; const int N = 1e6 + 10; int b[N]; deque<int> a; //存下标 int main() { int n, k; cin >> n >> k; for(int i = 0; i < n; i++) cin >> b[i]; //min for(int i = 0; i < n; i++) { while(!a.empty() && b[a.back()] > b[i]) a.pop_back(); a.push_back(i); if(i - k >= 0 && b[a.front()] == b[i - k]) a.pop_front(); if(i + 1 >= k) cout << b[a.front()] << ' '; } a.clear(); cout << endl; //max for(int i = 0; i < n; i++) { while(!a.empty() && b[a.back()] < b[i]) a.pop_back(); a.push_back(i); if(i - k >= 0 && b[a.front()] == b[i - k]) a.pop_front(); if(i + 1 >= k) cout << b[a.front()] << ' '; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话