戏精剧场:
单调栈的自我介绍:
我是栈家族的一份子,但我和那些凡夫俗子不一样,我很特别,特别单调。要么单调增,要么单调减,我是一个有原则的——栈。
多说无益,直接上题:
下面为计蒜客上的一道题:
瞭望塔题目
题目:
在蒜国的海岸线上有一排由西向东的瞭望塔,这些瞭望塔由于建造的地面高度不相同,所以瞭望塔的高度也是可能不一样的。 这个时候蒜国国王来问蒜头君,每个瞭望塔向东看能看到几个瞭望塔?这里需要注意如果在塔 A 东边有一个 B 塔,B 塔的高度高于或等于 A 塔的高度,那么 A 塔是看不到 B 塔后面的塔,在海岸线上是没有其他的建筑高于瞭望塔的。
输入格式
第一行输入一个整数 n,表示有 n 个瞭望塔。 接下来一行有 n个整数 a_i ,表示由西向东的 n 个瞭望塔的高度。
输出格式
输出 n 个整数,分别表示第 i 个瞭望塔可以看到的瞭望塔的个数。
题目分析:
首先按照从西向东的顺序将瞭望塔一个一个入栈,标记它们是第几个瞭望塔,因为只要遇到比自己高的瞭望塔,从这一个开始,后面的也都看不到,所以入栈过程要保证栈内是递减的,这样,栈才是有效的。因此每次要入栈一个元素时,就与栈顶比较,一旦其比栈顶高,则将栈顶出栈,统计出栈元素能看到的瞭望塔的个数,统计方法就是当前要入栈元素的标记减栈顶元素的标记,然后再与新的栈顶比较,循环下去;如果其比栈顶低,那它肯定比栈内所有元素都低,此时可将它安心入栈,直到所有瞭望塔都入栈,此时统计栈中各元素能看到的瞭望塔个数,方法是栈顶元素的标记减去该元素的标记。
然后我们还是上图,以
5
4 3 5 2 1
为一组样例输入
则我们首先将1号瞭望塔入栈,此时栈顶元素的高度是4,其他瞭望塔排队等候,
然后叫号到2号,再将2号瞭望塔与栈顶元素的高度比较,发现2号瞭望塔屈居人后,安心入栈,如下图
接着叫到了3号,将3号瞭望塔与栈顶元素比较,显然栈顶实力不足,不配将3号瞭望塔收入栈中组成单调栈,于是悲愤离去,拿走了属于自己的耻辱印记,记录它能看到的瞭望塔个数的减法公式:3-2=1,可怜2号刚出门就遇到了比自己厉害的对手,于是眼中再也装不下别的塔,此时栈顶的宝座又回到1号瞭望塔手中,
3号还是跃跃欲试地要入栈,于是和新的栈顶元素也就是1号瞭望塔一争高下,1号选手惜败,临走时也拿走了属于自己的记录:3-1=2,此时栈空,3号选手无人能敌,于是大方入栈
紧接着叫到4号,4号选手与栈顶元素实力悬殊,只得乖乖入栈,而5号选手的水平甚至还在4号之下,于是平静地入栈,组成了优美的单调栈
至此所有瞭望塔都已入栈,是时候来一波年终清算了,按照公式,栈顶元素的号码减去自己的号码即为自己能看到的瞭望塔个数
最后,上
代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct
{
int no;
int height;
}stack;
int main()
{
int n;
scanf("%d", &n);
int *a = (int *)calloc(n, sizeof(int));
stack *st = (stack *)calloc(n, sizeof(stack));
int top = -1;
int *count=(int *)calloc(n,sizeof(int));
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
if (top == -1) {
top++;
st[top].height = a[i];
st[top].no = i + 1;
} else {
while (a[i] >= st[top].height && top > -1) {
count[st[top].no - 1] = i + 1 - st[top].no;
top--;
}
if (a[i] < st[top].height || top == -1) {
top++;
st[top].no = i + 1;
st[top].height = a[i];
}
}
}
for (int i = 0; i <= top; i++) {
count[st[i].no - 1] = st[top].no - st[i].no;
}
for (int i = 0; i < n; i++) {
printf("%d ", count[i]);
}
return 0;
}