接青豆 | 「青训营 X 码上掘金」主题创作活动

93 阅读2分钟

当青训营遇上码上掘金

本文为青训营 X 码上掘金活动项目,

地址:code.juejin.cn/pen/7199606…

题目

主题 4:攒青豆

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

image.png

题目分析

这道题和力扣上的一经典题非常类似

42. 接雨水 - 力扣(Leetcode)

解决这个问题的关键在于,使用合理的方法,把雨水分隔成若干小矩形,对面积求和。 例如,题中的雨水可以这样划分:

image.png

单调栈

基本思想

确定矩形的长:两个墙壁边界的下标之差

矩形的高:墙壁高度之差

类似括号匹配:遇到左括号就入栈,遇到右括号则弹出栈顶的括号,得到一对匹配的括号。

维护一个单调递减的栈,对墙壁的高度进行遍历:

如果当前高度大于栈顶高度,弹出栈顶元素,则说明可以构成一个目前最低的“容器”,此时容器的宽度为当前下标减去此时栈顶元素。

总体的原则:

1.当前高度小于等于栈顶高度,入栈,继续遍历。

2.当前高度大于栈顶高度,出栈,计算出当前墙当前栈顶的墙之间水的多少,然后比较当前的高度和新栈顶高度的关系,重复第 2 步。直到当前墙的高度不大于栈顶高度或者栈空,然后把当前墙入栈,指继续遍历。

复杂度分析

时间复杂度:虽然 while 循环里套了一个 while 循环,但是考虑到每个元素最多访问两次,入栈一次和出栈一次,所以时间复杂度是 O(n)O(n)O(n)。

空间复杂度:O(n),栈的空间

代码展示

class Solution {
public:
    int trap(vector<int>& height) {
        int res=0;
        stack<int> s;
        s.push(0);
        int n=height.size();
        for(int i=1;i<n;i++){
            
            while(!s.empty()&&height[i]>height[s.top()]){
                int m=s.top();
                s.pop();
                if(!s.empty())
              {  int width=i-s.top()-1;
                int high=min(height[i],height[s.top()])-height[m];
                res+=width*high;}
            }
            s.push(i);
        }
        return res;
    }

};