单调栈问题
提起单调栈,有一个很经典的问题:找出一串数字中任意一个数字左/右边最近的比该数小的数字。比如:有一串数字8 4 3 7 9 5,我们需要得到其中任意一个数字左边最近的比该数还要小的数字,那么对于这串数字我们返回的数字为-1 -1 -1 3 7 3。
最朴素的做法就是双重循环,第一重循环遍历每个数字,第二重循环遍历这个数字左边的数字,找出最近的比该数小的数字。
那么,单调栈是什么?我们如何用单调栈来解决此类问题?
数字有序地存储在栈中,单调栈有两种,一是单调递增栈,二是单调递减栈。
单调递增栈就是从栈底到栈顶数字由大变小。
单调递减栈就是从栈顶到栈底数字由大变小。
对于该题,当我们寻找7这个数字左边最近的比7小的数字的时候,我们可以把7前面的数字依次入栈,如果出现后入栈的数字比先入栈的数字小的情况,那么先入栈的数字将会被删掉。经过这些删除操作之后,栈中的数字呈现一种递增的趋势,这个时候我们去找离7这个数字最近的比7小的数就很容易了。
下面是参考y总算法基础课中的部分代码实现:
#include <iostream>
using namespace std;
const int N = 10010;
int main(){
int stk[N],tt;
int n;
cin>>n;
for(int i = 0;i<n;i++)
{
int x;
cin>>x;
while(tt&&stk[tt]>=x) tt--;//删除比x还要大的数字并且如果栈中有两个元素都比x小,前面的数比后面的数大,那么毫无疑问前面的数字也需要删掉,因为前面的数也根本用不着。
if(tt) cout<<stk[tt]<<' ';//输出最近的比该数小的数
else cout<<"-1"<<' ';//左边没有比该数小的
stk[++tt]=x;//将当前元素添加到栈中
}
}