给出N个数,如果一个数的右边相邻的那个数小于当前数,那么他右边这个数就会被删除。
问会进行多少轮次这个游戏。
思路:
这个题写一个链表也可以,但是常数相对大一些。
这里写一下单调栈的思路:
我们模拟一下单调栈就能理解了。假设有样例:
5 6 3 7 4 1 2
①首先将5放入栈,设定其价值为0.表示这个点现在左边没有比他大的点,也就是这个点不需要操作。
②然后将6放入栈,同时需要先将5弹出栈,现在栈内情况为:(6)同时设定其价值为0.
③然后将3放放入栈,现在栈内情况为:(6,3),此时我们设定3的价值为0+1.
④然后将7放入栈,同时弹出3和6,设定7的价值为0,现在栈内的情况为:(7);
⑤然后将4放入栈,现在栈内情况为:(7,4),我们此时设定4的价值为0+1.
⑥然后将1放入栈,现在栈内情况为:(7,4,1),我们此时设定1的价值为1+1=2.
⑦最后将2放入栈,同时弹出1,现在栈内情况为:(7,4,2),我们此时设定2的价值为1+1=2.
价值最大为2,所以整体需要2次操作。
所以我们每次操作的时候,先将栈内老元素弹出,同时维护弹出的元素的最大价值(maxn),那么我们此时再加入栈内的元素的价值就是这个最大价值+1(maxn+1),表示我们这个当前数字操作的次数是要接着之前几个数进行的。如果没有弹出操作,那么对应maxn就是0.
过程维护一下即可。
具体内容参考代码。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<stack>
using namespace std;
struct node
{
int num,val;
}now,nex;
int a[150000];
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
stack<node>s;
int ans=0;
for(int i=1;i<=n;i++)
{
int sum=0;
while(s.size()>0)
{
now=s.top();
if(now.num<a[i])
{
s.pop();
sum=max(sum,now.val);
}
else break;
}
now.num=a[i];now.val=sum+1;
if(s.size()==0)now.val=0;
ans=max(ans,now.val);
s.push(now);
}
printf("%d\n",ans);
}
}