当青训营遇上码上掘金
题目分析
这题需要用到简单的动态规划。先对数组中的所有元素进行一次预处理:从右往左遍历找到每一根柱子右侧最高的柱子,再从左往右遍历找到每一根柱子左侧最高的柱子。对于每一柱子,能攒青豆的量就是左右两侧最高柱子的最小值与当前柱子的高度的差值,最后,将所有能接住的青豆数量相加。
思路模拟
求每一列能攒的青豆数,我们只需要关注当前列,左边最高的墙,右边最高的墙就够了。
青豆的数量,我们只需要看当前柱子左边最高的柱子和右边最高的柱子中较矮的一个的高度。
所以,根据较矮的那个柱子和当前列的柱子的高度可以分为三种情况。
- 较矮的墙的高度大于当前列的墙的高度 很明显,较矮的一边,也就是左边的柱子的高度,减去当前列的高度就可以了。
- 较矮的墙的高度小于当前列的墙的高度 正在求的列不会有青豆,因为它大于了两边较矮的墙。
- 较矮的墙的高度等于当前列的墙的高度。
和上一种情况是一样的,不会有青豆留下。
遍历每一列,然后分别求出这一列两边最高的墙maxl和maxr。找出较矮的一端,和当前列的高度比较,结果就是上边的三种情况。
这样遍历每一列左边最高的柱子和右边最高的柱子的时间复杂度是O(n^2)。
但是
我们注意到对于每一列,我们求它左边最高的柱子和右边最高的柱子(不包括自己),都是重新遍历一遍所有高度,这里可以优化。
首先利用两个数组,l[i]表示第i列柱子左边最高的柱子的高度,r[i]代表第i列柱子右边最高的柱子的高度。
对于l[i]可以遍历height,
l[i] = max(l[i - 1], height[i - 1])得到,同理r[i]可由r[i] = max(r[i + 1], height[i])得到,注意边界条件。这样,对于直接模拟无需每次重新遍历一次求maxl和maxr了。 最后对于每一列res += max(0, min(l[i], r[i]) - height[i - 1]),当前列表示左右两边最搞的柱子中更低的一个,减去当前列柱子的高度即是当前列可以攒的青豆数。 时间复杂度:O(n)。空间复杂度:O(n)。