当青训营遇上码上掘金
参加「青训营 X 码上掘金」主题创作活动攒青豆,激动的心颤抖的手。以前放寒假在家是吃饭、睡觉、打豆豆,有了青训营变成了吃饭、睡觉、攒青豆。
攒青豆
题目要求:现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
样例:
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
题目分析:
一看题目这不是接青豆吗(接雨水),看来青训营是想青豆撒下来看我们接不接的住喽。好在我练习时长两年半。一眼望去我一个左正蹬(单调栈),右手一个五连鞭(用单调栈计算面积差再累加即可),三下五除二搞定。
解题思路:
维护一个单调递减栈,当下一个柱子比栈顶柱子高的时候就依次弹出栈顶元素(直到栈顶元素比当前柱子高时为止),在弹出的过程中通过计算最矮柱子与前一个柱子的差作为高,当前柱子的下标减去栈顶柱子下标-1作为宽。就这样一直将所有都加起来就是最终结果。
代码
#include <bits/stdc++.h>
using namespace std;
int main (){
int n; cin >> n;
vector<int> height(n);
for(int i = 0; i < n; i++) cin >> height[i];
stack<int> stk; // 单调栈
int res = 0;
for(int i = 0; i < height.size(); i++) {
int last = 0; // 记录前一个元素的高度,初始值是0方便计算
while(stk.size() && height[stk.top()] <= height[i]){
// 栈顶元素高度-前一个元素高度作为高
// 当前位置-栈顶位置-1作为宽
res += (height[stk.top()] - last) * (i - stk.top() - 1);
// 更新前一个位置
last = height[stk.top()];
stk.pop();
}
// 最后计算
if(stk.size()) res += (height[i] - last) * (i - stk.top() - 1);
stk.push(i);
}
cout << res << endl;
}
吃饭、睡觉、攒豆豆!!!加油!!!