单调栈简介
单调栈是一种基于栈的数据结构,类似于优先队列,顾名思义内部数据保持单调的数据结构,即单调递增或单调递减。
这里拿栈内数据严格单调递减来举例子。
单调栈同样是先进后出,首先读入一个数据,有两种情况:
一是如果栈为空,则直接把数据存入栈尾。
二是这个数据和栈尾作比较,如果大于等于栈尾,则把栈尾数据出栈,接着比较拿输入数据与新栈尾作比价,直到小于栈尾,则入栈。
可以用数组或者STL(链表)实现。
代码如下:
因为STL用起来更像易读,刚学想试下 ,所以就用STL写了,但是平时做题为了方便还是会用数组实现,其实就是插入排序的一部分
#include<stack>
using namespace std;
stack<int>sta;
void fun(int num[],int len) //要插入栈的数据
{
int t;
int i;
for(i=0;i<len;i++){
t=num[i];
while(!sta.empty()&&t>=sta.top()){ //判断
sta.pop();
//弹出栈顶后往往还要对这些数据作操作
//具体试情况而定,这里就不写了
}
sta.push(t); //入栈
}
}
简单还是简单,就是不知道啥时候用orz 所以拿一个裸题来找下感觉。
1.剪头发问题http://poj.org/problem?id=3250
题意:有n个身高输入,代表从左到右的每个人身高,每个人都向右看,但是只能看到比他身高矮(小于)的人的发型,并且视线会被中间更高的人挡住。
解法:可以从左到右读这组数据,构建一个栈内数据严格单调递减的单调栈,每有一个新元素入栈,意味着栈内原本的元素数量的人可以看到这个新元素。唯一要注意数据可能有爆int所以要用长整型。
所以AC代码:
#include<cstdio>
#define max_n 80005
const int INF=1e9+5;
using namespace std;
int h[max_n],ans[max_n];
int main()
{
long long int ans;
int end;
int n,t;
scanf("%d",&n);
h[0]=INF;
//一个技巧是把栈里第一个元素设置成INF,单调递增则是设置成-INF
ans=end=0; //end代表栈顶的下标
while(n--){
scanf("%d",&t);
while(t>=h[end]){ //判断
end--;
}
ans+=end; //加上之前栈内有多少个元素
h[++end]=t; //入栈
}
printf("%lld\n",ans);
return 0;
}
因为每个元素有一次入栈和出栈所以复杂度为O(2n)。