当青训营遇上码上掘金
主题:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
输入: heights = [5, 0, 2, 1, 4, 0, 1, 0, 3]
输出: 17
解释: 可见上方图片展示,最多可以盛放 17 单位的青豆。
该题实质上就是接雨水问题,具体题目可以参照42. 接雨水 - 力扣(LeetCode)。
题意分析
1.数组的最左和最右的上面都不可能容纳青豆,因为其左边和右边不存在屏障为他们保存青豆, 所以我们只需要考虑除最左和最右位置上的存青豆
2.分析数组每位上的存豆量,需要考虑当前位置的左边最高屏障,以及右边最高屏障,只有依靠左右屏障才能 在当前位置存储青豆
可以得到如下公式:
左右最高中的最小值-当前位置的高度=当前位置上的存豆量
依照上述题意有两种解题思路:
1.dp,直接使用两个数组保存每个位置的左右最高屏障,这样的空间开销是O(n)
2.双指针,直接使用两个变量保存每个位置的左右最高屏障,在动态的移动过程中更新左右最高值,空间开销是O(1)
两种方法的时间开销都是O(n)
题解:
-
动态规划
对于数组 height 中的每个元素,分别向左和向右扫描并记录左边和右边的最大高度,然后计算每个下标位置能接的雨水量。 假设数组height的长度为 n,该做法需要对每个下标位置使用 O(n) 的时间向两边扫描并得到最大高度, 因此总时间复杂度是 O(n^2)代码实现:
-
双指针
当前列所能容纳所能容纳的最大青豆数取决于其左右两侧的最高屏障的较小值再减去当前屏障的高度。 基于该思路设置左右指针分别指向数组两侧(只能向内移动), 同时设置leftmax,rightmax表示左右指针移动过程中的最大高度。移动左右指针,移动过程更新leftmax,rightmax。 存在下述情况: 1.leftmax>=rightmax 左侧最大高度大于右侧,则当前列容纳数量等于右侧最大高度减去当前列高度 2.rightmax<leftmax 右侧最大高度大于左侧,则当前列容纳数量等于左侧最大高度减去当前列高度代码实现: