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

74 阅读2分钟

当青训营遇上码上掘金

题目描述

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

image.png 示例:

输入:height = [5,0,2,1,4,0,1,0,3]

输出:17

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

分析

这道题的“青豆”🫒不得不说和青训营主题非常契合hhh不过别看它看起来非常奇异,这其实本质就是知名题目“接雨水”的变种嘛23333

接下来就简单分析下咯

1.暴力

直观上看,对于每个柱子,它自身能接到的青豆量其实就是他本身及他左边最高的柱子的高度和他本身及他右边最高的柱子的高度做差,再减去他本身的高度。 所以大概流程就是遍历height数组,然后每次再遍历数组最左边到当前位置更新left_max,以及遍历当前位置到数组最右边更新right_max,然后计算当前柱子能攒的青豆数量并累加到总数量上。

代码如下:

(附链接不能凑字数aaaaa)

时间复杂度:O(n^2) 空间复杂度:O(1)

2.动态规划

对于下标i,洒落豆子之后,豆子能达到的最大高度是下标i两边的最大高度的最小值,故下标i处能接的豆子数量是下标i处能达到的最大高度减去height[i]

在暴力的做法中我们在每个位置都进行了向左和向右的两次扫描,那我们为什么不提前进行扫描,记录并存储每个位置两边的最大高度呢?

我们创建一个left_max[len]和一个right_max[len],用来存储每个位置对应的left_max[i]和right_max[i],我们通过动态规划获得这个数据。

  • 正向遍历数组时,left_max[i] = max(left_max[i - 1], height[i])
  • 反向遍历数组时,right_max[i] = max(right_max[i + 1], height[i])

最后遍历一遍,用每个位置二者的最小值减去这个位置柱子的高度 代码如下: 时间复杂度:O(n) 空间复杂度O(n) 当然啦,这道题还有别的解法,比如用单调栈,或者用双指针。不过由于时间原因(我困了)就略过啦