「青训营 X 码上掘金」主题4:攒青豆

50 阅读2分钟

当青训营遇上码上掘金

1 题目要求

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

输入

height = [5,0,2,1,4,0,1,0,3] 

输出

17 

2 思路

这道题可以用一种朴素的想法,对于每一列分别考虑能装青豆的数量,先求出每一列能装的青豆数量,再求和即可得到最终能装的青豆数量。这里我采用了动态规划的思路求解。

创建两个长度为 n(n是所有柱子的宽度) 的数组 leftMax 和 rightMax 。其中 leftMax 每个元素代表该柱子自身及左边所有柱子的最大高度,即当0≤i<n时,leftMax[i] 表示下标 i 及其左边的柱子中,height 的最大高度。同理 rightMax[i] 表示下标 i 及其右边的柱子中,height 的最大高度。

关于数组 leftMax 和 rightMax 取值的计算,显然 leftMax[0]=height[0],rightMax[n−1] = height[n−1]。两个数组的其余元素采用如下所示方式进行计算:

  • 当 1 ≤ i ≤ n−1 时,leftMax[i] = max ( leftMax[i−1] , height[i] );

  • 当 0 ≤ i ≤ n−2 时,rightMax[i] = max ( rightMax[i+1] , height[i] )

从左往右遍历,依次计算leftMax[i]的值,最终可得到leftMax;从右往左遍历,依次计算rightMax[i],最终可得到rightMax。

这些计算的结果将作为计算青豆数量的参数,同时也不难看出这一步的时间复杂度是O(n),空间复杂度显然也是O(n)。

在得到数组 leftMax 和 rightMax 的每个值之后,就可分别求出每一列的能装的青豆数量了。对于 0 ≤ i < n,每一个柱子 i 处能接的青豆数量可以按照此公式得到:

    num[i] = min ( leftMax[i] , rightMax[i] ) − height[i]

因此,最后再遍历每个i,求出每一列能装的青豆数量,将所有列的数量求和,即可得到能接的所有青豆数量。最后求和的时间复杂度是O(n),空间复杂度是O(1)

因此,可以看出动态规划求解的时间复杂度是O(n),空间复杂度是O(n)。但动态规划方法并不算优秀,其他的方法比如双指针法空间复杂度能达到O(n)

3 代码