这个坑好大,先写个大概,以后慢慢填 orz
首先:单调栈是一种特殊的栈,特殊之处在于栈内的元素都保持一个单调性。
“单调” “栈”,从字面意思来看,跟单调有关,跟栈有关。单调的含义学了数学的都知道指的是函数的单调性,也就是一直增/减,例如1,2,3,4就是一个单调递增的数列,单调栈中的元素就有这样的性质。
以单调递增栈为例,比如数组:2 7 1(图很丑麻烦见谅)
简易代码如下:
while(s.empty()) s.pop(); //先清空栈
a[n]=-1;
for(i=0;i<=n;i++){
if(s.empty()||a[j]>=a[s.top()]){ //如果栈为空或入栈元素大于等于栈顶元素,则入栈
s.push(j);
}
else{
while(!s.empty()&&a[j]<a[s.top()]){ //如果栈非空并且入栈元素小于栈顶元素,则将栈顶元素出栈
top=s.top();
s.pop();
}
s.push(top); //将最后一次出栈的栈顶元素延伸并入栈
a[top]=a[j]; //修改其对应的值
}
}
以上是用STL中的栈实现的,用模拟栈也是可以的,单调栈不仅仅可以存数组元素,也可以存放数组下标而栈内元素并不单调(即下标单调),这就需要对单调栈的灵活运用了
POJ2559
这个题目基本意思是求出直方图中最大的矩形面积,思路为建立一个单调递增栈,所有元素逐个进栈,出栈时更新最大矩形面积。
输入样例:
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
输出样例:
8
4000
栈空,2进栈,当前最大面积为2。1准备进栈,此时1比2小,弹栈操作,2出栈,1进栈,更新最大面积仍为2,栈内元素为1,剩下高为1,宽为2的矩形;4进栈,5进栈,1进栈进栈前为满足单调递增,5出栈时更新最大矩形面积为2*4 = 8,紧接着4也出栈,矩形面积为4(<8,不必更新),故最大矩形面积仍为8,栈内元素为1,1,剩下高为1,宽为5的矩形;接着两个3依次进栈,无弹栈操作,直到没有元素进栈。弹出余下元素。最后答案为8。
代码如下:
#include
#include
#include
#define N 100005
using namespace std;
int main(){
int n;
long long a[N],b[N];
while(scanf("%d", &n) != EOF && n){
long long ans = 0;
for(int i = 1;i <= n;++i) {
scanf("%d", &a[i]);
}
stack<int> s;
s.push(n+1);
a[n+1] = -1;
for(int i = n;i>0;--i){
while(a[s.top()] >= a[i])
s.pop();
b[i] = s.top();
s.push(i);
}
while(!s.empty()){
s.pop();
}
s.push(0);
a[0] = -1;
for(int i = 1;i <= n;++i){
while(a[s.top()] >= a[i])
s.pop();
ans = max(ans, a[i]*(b[i]-s.top()-1));
s.push(i);
}
cout << ans << endl;
}
return 0;
}
POJ3494:
这题大致意思是找到最大的全一矩阵,属于二维的单调栈问题,需要先进行预处理,若当前行为1,则当前行在上一行的基础上累加1,否则为0,每行都用单调递减栈进行处理,方法类似于2559,具体代码如下:
#include
#include
#include
#include
using namespace std;
int main(){
int i,j,m,n,x,top,tmp,ans,h[2020],a[2020];
stack<int> s;
while(~scanf("%d%d",&m,&n)){
ans=0;
memset(h,0,sizeof(h));
for(i=0;i<m;i++){
for(j=1;j<=n;j++){
scanf("%d",&x);
if(x==1){
h[j]++;
}
else h[j]=0;
a[j]=h[j];
}
a[n+1]=-1;
for(j=1;j<=n+1;j++){
if(s.empty()||a[j]>=a[s.top()]){
s.push(j);
}
else{
while(!s.empty()&&a[j]<a[s.top()]){
top=s.top();
s.pop();
tmp=(j-top)*a[top];
if(tmp>ans) ans=tmp;
}
s.push(top);
a[top]=a[j];
}
}
}
cout << ans << endl;
}
return 0;
}
牛客第一场A题:
从左到右遍历一遍,记录下第一个单调栈结果不同的地方,该位置前一个位置就是结果。
#include
#define MAX 100000
using namespace std;
int main(){
int n;
while(~scanf("%d",&n)){
int a[MAX],b[MAX];
stack<int> s1,s2;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<n;i++){
scanf("%d",&b[i]);
}
int num=1;
s1.push(a[0]);
s2.push(b[0]);
while(1){
if(num==n){
printf("%d\n",num);
break;
}
while(1){
if(!s1.empty()){
if(s1.top()>a[num]){
s1.pop();
}
else{
s1.push(a[num]);
break;
}
}
else {
s1.push(a[num]);break;
}
}
while(1){
if(!s2.empty()){
if(s2.top()>b[num]){
s2.pop();
}
else{
s2.push(b[num]);
break;
}
}
else {
s2.push(b[num]);break;
}
}
if(s1.size()==s2.size()){
num++;
}
else{
printf("%d\n",num);
break;
}
}
}
return 0;
}
与单调栈的定义相似,单调队列就是队内元素符合单调性质的队列,而且队首队尾都可以进行出队操作,只有队尾可以进行入队操作