单调栈
从栈底到栈顶,元素的值单调增加(递增栈)或单调减小(递减栈),多用于求解左右大小边界问题
- 向左找第一个比自身大的数
- 向左找第一个比自身小的数
- 向右找第一个比自身大的数
- 向右找第一个比自身小的数
概念
维护单调栈:只需要将要入栈的数据和栈顶比较
1. 若符合条件,直接入栈
2. 若不符合条件,将栈顶出栈,直到符合条件为止
用单调栈解决左右大小边界问题两种思路
栈顶为答案
找左边第一个比自己大的数
- 从左到右遍历,用递减栈保存已经遍历过的数
- a[i]符合入栈条件时栈不为空,则第一个比a[i]大的数就是此时栈顶元素
- a[i]符合入栈条件时栈为空,说明a[i]左边没有比a[i]大的数
- 不符合入栈条件就连续出栈栈顶元素,直到符合入栈条件
由于出栈的数都是比后面的要入栈数小,所以一定不符合要找的第一个比自己大的数条件,不会漏掉答案
模板
#include <iostream>
#include <stack>
using namespace std;
//向左找第一个比自己大的数
int n; //n<=100
int a[105];
int ans[105]; //答案数组
stack<int> s;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
while (!s.empty() && s.top() <= a[i])s.pop();
if (s.empty())ans[i] = -1; //表示左边没有比a[i]大的数
else {
ans[i] = s.top();
}
s.push(a[i]);
}
//输出答案
for (int i = 1; i <= n; i++) {
cout << ans[i] << " ";
}
cout << endl;
return 0;
}
找左边第一个比自己小的数
- 从左到右遍历,用递增栈保存已经遍历过的数
- a[i]符合入栈条件时栈不为空,则第一个比a[i]小的数就是此时栈顶元素
- a[i]符合入栈条件时栈为空,说明a[i]左边没有比a[i]小的数
- 不符合入栈条件就连续出栈栈顶元素,直到符合入栈条件
找右边第一个比自己大的数
- 从右到左遍历,用递减栈保存已经遍历的数
- a[i]符合入栈条件时栈不为空,则第一个比a[i]大的数就是此时栈顶元素
- a[i]符合入栈条件时栈为空,说明a[i]左边没有比a[i]大的数
- 不符合入栈条件就连续出栈栈顶元素,直到符合入栈条件
找右边第一个比自己小的数
- 从右到左遍历,用递增栈保存已经遍历的数
- a[i]符合入栈条件时栈不为空,则第一个比a[i]小的数就是此时栈顶元素
- a[i]符合入栈条件时栈为空,说明a[i]左边没有比a[i]小的数
- 不符合入栈条件就连续出栈栈顶元素,直到符合入栈条件
当前遍历到的数为答案
找左边第一个比自己大的数
- 从右到左遍历,用递减栈存已经遍历的数
- a[i]符合入栈条件直接入栈
- a[i]不符合入栈条件,说明此时要出栈的栈顶元素的答案就是此时的a[i]
- 遍历完所有数后,若栈非空,栈中的所有元素没有答案
模板
#include <iostream>
#include <stack>
using namespace std;
//找左边第一个比自己大的数
int n; //n<=100
int a[105];
int ans[105];
stack<int> s;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = n; i >= 1; i--) {
while (!s.empty() && a[s.top()] < a[i]) {
ans[s.top()] = a[i];
s.pop();
}
s.push(i); //入栈下标
}
while (!s.empty()) {
ans[s.top()] = -1;
s.pop();
}
for (int i = 1; i <= n; i++) {
cout << ans[i] << " ";
}
cout << endl;
return 0;
}
- 其他三种同理

浙公网安备 33010602011771号