题意:找到每个数后面第一个大于它的元素的下标
可以比喻成站了一队人,每个人向右看,求他们每个人看到的第一个人的位置
顾名思义,单调栈就是栈内元素具有单调性,其维护的就是一个数前/后第一个大于/小于他的数
我们将输入的数列a[]倒着遍历一下(要找每个数后面的第一个比它大的数,从后向前入栈可以实现),入栈的第一个数也就是数列的最后一个,它的对应函数值一定为0。倒数第二个入栈,和栈顶元素即它后面元素(即最后一个元素)相比,若比它大,栈顶元素就出栈,否则这个倒数第二个元素就正常入栈......
有一个问题是,这样就能保证求出的是第一个大于的数吗?
假设我们已经求出了ai的函数值fi,对于aj(aj<=ai)来说(只需考虑 j<i 的情况),ai一定不会对f1、f2、...、fj有影响,可能i对于aj是一个解,但也许在1...j-1中有更好的解。也就是O(n^2)暴力枚举的思想,找到一个比它大的数就退出;于是,我们对于整个序列都用贪心维护一个栈保存可能有用的元素下标,若栈顶对应元素比当前元素不大,贪心,然后弹出栈顶的下标。直到栈顶对应元素比当前元素大了,就说明不能继续贪心了,记录答案(重点,最靠前可行的元素就是栈顶对应的元素)。最后将当前下标加入栈。
#include <iostream>
#include <cstdio>
#include <stack>
#include <algorithm>
using namespace std;
const int maxn=3000001;
int a[maxn],f[maxn];
int main()
{
int n;
//cin>>n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]); //cin>>a[i];
stack<int> s;
int i=1;
/*bool flag;//true means no one bigger than itself
while(i<=n)
{
flag=true;
s.push(a[i]);
i++;
for(int j=i;j<=n;j++)
{
if(a[j]>s.top())
{
flag=false;//not the "biggest"
//cout<<j<<' ';
printf("%d ",j);
break;
}
}
if(flag) printf("0 ");//cout<<0<<' ';
}*/
for(int i=n;i>=1;i--)
{
while(!s.empty()&&a[s.top()]<=a[i]) s.pop();
f[i]=s.empty()?0:s.top();
s.push(i);
}
for(int i=1;i<=n;i++) printf("%d ",f[i]);
return 0;
}
本文介绍如何使用单调栈高效地解决寻找数组中每个元素后方第一个更大的元素的问题。通过从后往前遍历数组并利用栈来维护可能的候选元素,实现了一种线性时间复杂度的解决方案。
1849

被折叠的 条评论
为什么被折叠?



