当青训营遇上码上掘金之攒青豆

74 阅读2分钟

当青训营遇上码上掘金

🤯自从进了青训营,我梦里做梦都是在攒青豆……

攒青豆

题目

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

攒青豆.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

实际上稍微刷过一点题目的都看出来了,这就是经典题目 接雨水 的变体,分类是困难,但是这种经典题目往往考多了大家也就都会了反而不难了。题目把雨水改成了青豆(哪里可以下青豆雨啊喂)

实际解决方法都是大同小异的,解决方法有很多,可以按行扫描也可以按列扫描,还可以用动态规划,这里我使用的方法是单调栈

题解

单调栈

即在栈中元素一定是单调递增或递减的,如果即将存放的数据违反单调性,则将栈中元素依次弹出,直至满足为止。栈中可以装载对应值,也可以装下标等信息,本题计算装青豆宽度时需要频繁使用下标,因此装下标而不是元素值

由于能接住青豆的部分一定是凹型的,所以单调递减的部分不需要过多关心,直接入栈就 OK,但是如果遇到递增的元素——也就是比栈顶部元素更大,就需要计算其能装入的青豆值了:

我们将顶部元素命名为 top,倒数第二个元素命名为 pre,目前元素下标与对应值为 iv

此时装青豆的宽度为:i-pre-1

装青豆的高度取决于其两边最矮的值:h=min(height[pre],v)-height[top]

这里其实可以抽象理解为每次计算青豆后,原本的空缺就被填补了,因此应该将空缺部分(top)弹出栈,下次计算时,就不会把这一部分重复计算。

主要有两个需要特别注意的边界值:

  • 单调栈中无元素时,应当直接入栈
  • 单调栈中只剩一个元素时,不需要计算青豆装填量而应该直接弹出