当青训营遇上码上掘金
本文为青训营 X 码上掘金活动项目,
题目
主题 4:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
题目分析
这道题和力扣上的一经典题非常类似
解决这个问题的关键在于,使用合理的方法,把雨水分隔成若干小矩形,对面积求和。 例如,题中的雨水可以这样划分:
单调栈
基本思想
确定矩形的长:两个墙壁边界的下标之差
矩形的高:墙壁高度之差
类似括号匹配:遇到左括号就入栈,遇到右括号则弹出栈顶的括号,得到一对匹配的括号。
维护一个单调递减的栈,对墙壁的高度进行遍历:
如果当前高度大于栈顶高度,弹出栈顶元素,则说明可以构成一个目前最低的“容器”,此时容器的宽度为当前下标减去此时栈顶元素。
总体的原则:
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;
}
};