每日一题——接雨水(单调栈)

接雨水——单调栈

题目链接


单调递增的栈还是单调递减的栈

我们常说的**”积水成洼“**,指的就是说:当两边地势高于中间的地势时,中间的区域就成了洼地,也就可以积水了。

这一题就是如此,我们需要通过一个栈来记录数据,只要记录的数据有高——低——高这一过程,就说明形成了洼地,也就可以计算雨水容量了。

所以我们应该用一个非递增的栈来存放数据,我们保证栈中的数据是非递增的,这样当一个数据准备进栈时,如果进栈元素小于栈顶元素,那就仍旧满足非递增顺序,直接入栈即可,而如果进展元素大于栈顶元素,就说明栈顶元素的前一个元素,栈顶元素,进栈元素这三个元素达成了高——低——高这一条件,也就可以进行容量的计算了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l92srQHv-1692435320269)(C:/Users/HUASHUO/AppData/Roaming/Typora/typora-user-images/image-20230819154920085.png)]


实现思路

我们已经知道要用非递增的单调栈来解决这个问题,那么接下来就要讨论如何做具体的实现了。

这里我们利用栈来储存数组元素的下标

规定栈顶元素为stack_top,栈顶元素的前一个为left(注意:二者都是构成容器的数组元素的下标

我们用i来遍历构成容器的数组,需要分以下几种情况讨论:

  • 当栈为空或者进栈元素小于栈顶元素时,进栈元素height[i]直接入栈即可。如图:

  • 否则,当栈不为空并且进栈元素大于栈顶元素时,为保证栈的非递增特性,要通过循环不断移除栈元素,同时:

    • 如果出栈顶元素后栈为空,那么直接将进栈元素height[i]入栈即可。如图:

    • 如果出栈顶元素后栈不为空,那么栈顶元素的前一个元素height[left]、栈顶元素height[stack_top]、进栈元素height[i]就达成了高——低——高的条件,即形成了积水区域。积水区域的宽wide就是i - left - 1,高度high就是min(height[i], height[left] - height[stack_top]),最后容积也就是wide * high。如图:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c7OeWwOf-1692435320269)(C:/Users/HUASHUO/AppData/Roaming/Typora/typora-user-images/image-20230819162535236.png)]

接下来,我们以题目中的例子height = [0,1,0,2,1,0,1,3,2,1,2,1]为例,模拟整个过程。

实现代码

int trap(int* height, int heightSize){
    //申请栈空间
    int *stack = (int*)malloc(sizeof(int) * heightSize);
    int top = 0;

    int volum = 0;  //容量

    for (int i=0; i<heightSize; i++)
    {
        //如果栈不为空并且遍历元素大于栈顶元素
        //由于要保证栈的单调性,所以无论如何栈顶元素都要出栈
        while (top != 0 && height[i] > height[stack[top - 1]])
        {
            int stack_top = stack[--top];

            //如果栈顶元素出栈后仍不为空,就说明可以容纳雨水
            if (top != 0)
            {

                //计算容量
                int left = stack[top - 1];
                int wide = i - left - 1;
                int high = fmin(height[left], height[i]);

                volum += wide * (high - height[stack_top]);
            }

            //如果计算完这一次后仍满足循环条件,就说明还可能继续装水
        }
        //无论是否进入循环,遍历元素都要入栈
        stack[top++] = i;
    }

    //释放栈空间
    free(stack);
    return volum;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Forward♞

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

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

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

打赏作者

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

抵扣说明:

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

余额充值