菜鸡学习笔记:单调栈的应用——瞭望塔

戏精剧场:

单调栈的自我介绍:
我是栈家族的一份子,但我和那些凡夫俗子不一样,我很特别,特别单调。要么单调增,要么单调减,我是一个有原则的——栈。

多说无益,直接上题:

下面为计蒜客上的一道题:
瞭望塔题目
题目

在蒜国的海岸线上有一排由西向东的瞭望塔,这些瞭望塔由于建造的地面高度不相同,所以瞭望塔的高度也是可能不一样的。 这个时候蒜国国王来问蒜头君,每个瞭望塔向东看能看到几个瞭望塔?这里需要注意如果在塔 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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸡报到

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值