当青训营遇上码上掘金
题目
主题 4:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
思路
使用单调栈,单调栈常见模型:找出每个数左边离它最近的比它大/小的数。
int tt = 0;
for(int i = 1; i <= n; i++) {
while(tt && check(stk[tt],i)) tt--;
stk[++tt] = i;
}
- 单调栈分为单调递增栈和单调递减栈
- 单调递增栈即栈内元素保持单调递增的栈
- 同理单调递减栈即栈内元素保持单调递减的栈
- 这里我们选择单调递减栈
- 当后面的柱子高度低于前面的,无法兜住青豆。
- 当找到一根比前面高的柱子,开始计算攒的青豆。
- 对于位置靠后,但是柱子比前面低的柱子,直接入栈
- 当出现比栈顶更高的柱子时,
- 收集前面柱子攒的青豆
- 取栈顶元素,保存cur,出栈。
- 取底 为当前柱子与当前栈顶柱子的距离
- 高为cur 和当前柱子与当前栈顶柱子最小值 的差值
- 计算收集的青豆,底 * 高
- 将栈顶比当前的柱子更低的柱子出栈
- 收集前面柱子攒的青豆
- 循环,直到最后一根柱子
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int res;
int a[N];
int stk[N] ,tt;
int main() {
for(int i = 1; (scanf("%d", &a[i]))!=EOF; i++) {
// scanf("%d", &a[i]);
while(tt && a[i] > a[stk[tt]]) {
int cur = stk[tt--];
if(!tt) break;
int s = i - stk[tt] - 1;
int h = min(a[stk[tt]], a[i]) - a[cur];
res += s * h;
}
stk[++tt] = i;
}
printf("%d", res);
return 0;
}