单调栈就是在栈的基础上保持了数的有序。
最常见的应用是用来求一个序列/数组中,每个数的左边/右边第一个比其小/大的数的位置。
例如找一个数组中每一个数的前面最近的比其小的数:
4, 6, 8, 7, 5
首先维护一个栈stk
,从前往后找每个数的答案,在找7
这个数的时候,此时栈中已经保存了4, 6, 8
这三个数了,首先比较栈顶元素8
,大于7
,弹栈,以后8
不会再是7
后面的任意一个数的答案,因为7<8
,而且7
距离它们更近。然后比较下一个数6<7
,即7
的答案是6
,然后将7
入栈供后面的数比较。
基于此,在找后面数的答案的时候就不需要再与8
进行比较了,如果数据量比较大(例如4, 6, 8, 8, 8, 8, 8, ..., 8, 7, 5, ...
,7
的后面的数不会再与8
进行比较),将会节省很大一部分时间。
因此可以发现栈stk
中的每个数是严格按照递增的顺序的,所以称为单调栈。
// 求右边第一个比其大的数
vector<int> ans(T.size(), 0);
stack<int> s;
for(int i = 0; i < T.size(); i ++ )
{
while(!s.empty() && T[s.top()] < T[i])
{
ans[s.top()] = i - s.top();
s.pop();
}
s.push(i);
}
// 求右边第一个比其小的数
vector<int> ans(T.size(), 0);
stack<int> s;
for(int i = 0; i < T.size(); i ++ )
{
while(!s.empty() && T[s.top()] > T[i])
{
ans[s.top()] = i - s.top();
s.pop();
}
s.push(i);
}
// 求左边第一个比其大的数
vector<int> ans(T.size(), 0);
stack<int> s;
for(int i = T.size() - 1; i >= 0; i -- )
{
while(!s.empty() && T[s.top()] < T[i])
{
ans[s.top()] = i - s.top();
s.pop();
}
s.push(i);
}
// 求左边第一个比其小的数
vector<int> ans(T.size(), 0);
stack<int> s;
for(int i = T.size() - 1; i >= 0; i -- )
{
while(!s.empty() && T[s.top()] > T[i])
{
ans[s.top()] = i - s.top();
s.pop();
}
s.push(i);
}
参考题:
https://www.acwing.com/video/258/
https://leetcode-cn.com/problems/daily-temperatures/
https://leetcode-cn.com/problems/next-greater-element-i/
https://leetcode-cn.com/problems/maximum-subarray-min-product/