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

58 阅读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 个单位的青豆。

方法一:双指针

注意到下标 i 处能接的青豆量由 leftMax[i] 和 rightMax[i] 中的最小值决定。由于数组 leftMax 是从左往右计算,数组 rightMax 是从右往左计算,因此可以使用双指针和两个变量代替两个数组。

维护两个指针 left 和 right, 以及两个变量 leftMax 和 rightMax , 初始时 left = 0, right = n - 1, leftMax = 0, rightMax = 0。指针 left 只会向右移动,指针 right 只会向左移动,在移动指针的过程中维护两个变量 leftMax 和 rightMax 的值。

当两个指针没有相遇时,进行如下操作:

  • 使用height[left]和height[right]的值更新 leftMax 和 rightMax 的值;
  • 如果height[left] < height[right],则必有 leftMax < rightMax ,下 标left 处能接的青豆量等于leftMax一 height[left],将下标left处能接的青豆量加到能接的青豆总量,然后将left 加1 (即向右移动一位);
  • 如果height[left] ≥height[right],则必有leftMax ≥ rightMax ,下标 right 处能接的青豆量等于 rightMax - height[right] ,将下标 right 处能接的青豆量加到能接的青豆总量,然后将right 减 1 (即向左移动一位)。

当两个指针相遇时,即可得到能接的青豆总量。

方法二:动态规划

对数组中的所有元素进行一次预处理:

  • 先从右往左遍历,找到每一根柱子右侧最高的柱子;
  • 再从左往右遍历,找到每一根柱子左侧最高的柱子。

因此,对于每一根柱子,能接住雨水的量,就是左右两侧最高柱子的最小值与当前柱子的高度的差值,最后,将所有的柱子能接住的雨水量相加即可。

代码:code.juejin.cn/pen/7199558…