攒青豆 | 「青训营 X 码上掘金」主题创作

67 阅读2分钟

当青训营遇上码上掘金

主题 4:攒青豆

1.主题描述

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

image.png

2.我的思路

本题和leetcode上的热题接雨水十分相似,我一开始就想起了最简单直接的解法. 我们采用对于每个下标 i, 分别计算它能够接到的水量, 最后将它们相加在一起.

接下来就是每个下标 i 青豆数的计算过程了, 从图中我们可以看出, 一个位置要想接到青豆, 那么两边必然要有比它更高的柱子, 并且能到达的最大高度等于下标 i 两边的最大高度的最小值, 而下标 i 处能接的青豆数等于下标 i 处的水能到达的最大高度减去 height[i].

这就是最重要的青豆数的计算过程了, 明白了这个原理之后, 我们只需要分别向左和向右扫描并记录左边和右边的最大高度, 然后计算每个下标位置能接的青豆数.

这就是常规思想的全部思路了, 这个方法会用到两次循环, 时间复杂度就达到了O(n^2), 接下来就是我们的优化过程了.

3.动态规划

上述做法的时间复杂度较高是因为需要对每个下标位置都向两边扫描。如果已经知道每个位置两边的最大高度, 则可以在 O(n) 的时间内得到能接的青豆总数. 所以我们可以用动态规划的方法提前得到每个位置两边的最大高度.

创建两个数组leftMax和rightMax.leftMax[i]表示下标i及其左边位置中,height的最大高度.rightMax[i]表示下标i及其右边边位置中,height的最大高度.

当1<=i<=n-1时,left[i]=max(leftMax[i-1],height[i]) 当0<=i<=n-2时,right[i]=max(rightMax[i+1],height[i])

一般来说, 动态规划的题目在遍历结束之后就能得到结果了, 但是本题还是需要对动态规划的结果进行进一步的处理才能得到最终的结果.

在得到数组 leftMax 和 rightMax 的每个元素值之后, 对于0<=i<n, 下标i处能接的青豆数等于min(leftMax[i],rightMax[i])−height[i]。遍历每个下标位置即可得到能接的青豆总数.

代码如下 将时间复杂度优化到了O(n)