当青训营遇上码上掘金
🤯自从进了青训营,我梦里做梦都是在攒青豆……
攒青豆
题目
- 现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
实际上稍微刷过一点题目的都看出来了,这就是经典题目 接雨水 的变体,分类是困难,但是这种经典题目往往考多了大家也就都会了反而不难了。题目把雨水改成了青豆(哪里可以下青豆雨啊喂)
实际解决方法都是大同小异的,解决方法有很多,可以按行扫描也可以按列扫描,还可以用动态规划,这里我使用的方法是单调栈
题解
单调栈
即在栈中元素一定是单调递增或递减的,如果即将存放的数据违反单调性,则将栈中元素依次弹出,直至满足为止。栈中可以装载对应值,也可以装下标等信息,本题计算装青豆宽度时需要频繁使用下标,因此装下标而不是元素值
由于能接住青豆的部分一定是凹型的,所以单调递减的部分不需要过多关心,直接入栈就 OK,但是如果遇到递增的元素——也就是比栈顶部元素更大,就需要计算其能装入的青豆值了:
我们将顶部元素命名为
top,倒数第二个元素命名为pre,目前元素下标与对应值为i和v
此时装青豆的宽度为:i-pre-1
装青豆的高度取决于其两边最矮的值:h=min(height[pre],v)-height[top]
这里其实可以抽象理解为每次计算青豆后,原本的空缺就被填补了,因此应该将空缺部分(top)弹出栈,下次计算时,就不会把这一部分重复计算。
主要有两个需要特别注意的边界值:
- 单调栈中无元素时,应当直接入栈
- 单调栈中只剩一个元素时,不需要计算青豆装填量而应该直接弹出