1. 传送门
学习传送门:单调栈 b站 up麦克老师讲算法
2. 笔记内容
2.1 应 用
求解下一个大于x元素或是小于x元素的位置
2.2 示 例
给定一个数组a,计算后获得一个大小相同的数组res,res数组的第i个值对应a数组第i个位置的元素,res[i]的值表示a[i]之后的第几个元素比a[i]大(如果之后没有比a[i]大的元素,或者当前元素已经是最后一个元素,则在res数组的对应位置放上-1)
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
a数组 | 1 | 3 | 4 | 5 | 2 | 9 | 6 |
res数组 | 1 | 1 | 1 | 2 | 1 | -1 | -1 |
res2数组 | 3 | 4 | 5 | 9 | 9 | -1 | -1 |
表中a数组为原数组元素,res数组用来存储下一个大于目前所指元素的元素下标与当前下标的距离(如果不存在满足条件的元素则该位用-1填充),res2数组用来存储下一个大于目前所指元素的元素值(不存在满足条件的元素也用-1填充)。
2.2.1 使 用 方 式
代码思想:从后向前遍历a数组,最后一个元素直接入栈res2填-1,从倒数第二个元素开始判断栈顶元素是否小于等于遍历到的元素,若栈顶元素小于等于遍历到的元素,则将栈顶元素出栈,循环判断栈中元素,直到栈为空或者栈中元素大于当前元素,判断当前栈是否为空,如果栈为空则将-1填入当前元素对应的res2数组位置中,如果栈非空则将栈顶元素填入res2。
void nextGreater(int a[], int n) {
stack<int> s;
for(int i = n - 1; i >= 0; --i) {
while(s.size() && s.top() <= a[i]) {
//当栈非空并且栈顶元素小于等于当前遍历到的元素将栈顶元素出栈
s.pop();
}
res2[i] = s.empty() ? -1 : s.top();
//当单调栈为空(在该元素之后没有比它大的元素)res数组中填入-1
//当单调栈非空(栈顶元素为比该元素大的后一个元素)res数组中填入栈顶元素
s.push(a[i]);
//将当前元素入栈
}
}
Tip:
通过while循环保证栈中元素都大于当前元素。
2.2.2 整 体 代 码 实 现
#include <iostream>
#include <stack>
using namespace std;
struct node {
int index;
int data;
};
int res[10];
void nextGreater(int a[], int n) {
stack<node> s;
for (int i = n - 1; i >= 0; --i) {
while (s.size() && s.top().data <= a[i]) {
s.pop();
}
res[i] = s.empty() ? -1 : s.top().index - i;
node temp;
temp.index = i;
temp.data = a[i];
s.push(temp);
}
}
int main() {
int num[7] = {1, 3, 4, 5, 2, 9, 6};
nextGreater(num, 7);
for (int i = 0; i < 7; ++i) {
if (i != 0)
printf(" ");
printf("%d", res[i]);
}
return 0;
}
3. 试一试
代码
#include <iostream>
#include <stack>
using namespace std;
struct node {
int index;
int data;
};
int res[3000001];
int num[3000001];
void nextGreater(int n) {
stack<node> s;
for(int i = n; i >= 1; --i) {
while(s.size() && s.top().data <= num[i]) {
s.pop();
}
res[i] = s.empty() ? 0 : s.top().index;
node temp;
temp.index = i;
temp.data = num[i];
s.push(temp);
}
}
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &num[i]);
}
nextGreater(n);
for(int i = 1; i <= n; ++i) {
if(i != 1) printf(" ");
printf("%d", res[i]);
}
return 0;
}