1. (当青训营遇上码上掘金)主题创作之——接青豆
当青训营遇上码上掘金
😻😻😻😻😻😻😻😻😻😻😻😻
🤚题目描述
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
采用方法:分析列 + 动态规划
问题的本身是求最终可以接到的青豆有多少,对于该问题,我们可以着眼于数组中每一根柱子的高度,本柱子上可以堆积多少青豆,取决于其左边最高柱子以及右边最高柱子,根据木桶效应,我们会选择其左边柱子以及右边柱子最低的那一个即可。
对于某一列以及其左右最高柱子,其大致可以分为两种情况:
-
当前柱子高度大于等于左右两侧柱子最低的那一个
在这种情况下,我们可以参考木桶效应,该柱子上并不会掉落青豆。
-
当前柱子高度严格小于左右两侧柱子最低的那一个
在该种情况下,该柱子上可以掉落对印的青豆,至于具体掉落的数量,我们不妨设左侧柱子最高柱子高度为LH,右边最高柱子高度为RH,正在求的列的柱子高度为MH,不难计算,该柱子上可以掉落的青豆数量为
引入动规思想:
有了上面关注列的思想之后,我们最简单暴力的做法可能就是设置两个数组, 与,
其中代表第i列左边最高的柱子,代表第i列右侧最高的柱子。对此两值的计算,直接暴力遍历数组得到两个的值,在这种情况下其复杂度为:
时间复杂度为:
空间复杂度为:
但是如果我们引入动态规划,换一种求解思路,可以明显的降低其时间复杂度,
-
对于,我们可以这样求解
. 在遍历的过程中,只需要确定其前边柱子的左边最高柱子高度以及其前边柱子的高度的最大值,即为当前列左边最高柱子。
-
对于 我们的求解方法与上面类似
. 在遍历的过程中,只需要确定其后边柱子的右边最高柱子高度以及其后边柱子的高度的最大值,即为当前列右边最高柱子。
这种思想下其复杂度为:
时间复杂度为:
空间复杂度为:
有了这样的思想之后,我们就可以着手写代码啦!!!! 😃😃
class Solution {
public int getQingDou(int[] height) {
int len = height.length;
int[] left = new int[len];
int[] right = new int[len];
// left 和 right分别代表左边和右边最高的柱子
left[0] = 0;
right[len - 1] = 0;
for(int i = 1 ; i < len ; i ++){
left[i] = Math.max(height[ i - 1],left[i - 1]);
}
for(int i = len - 2; i >= 0; i--){
right[i] = Math.max(height[i + 1],right[i + 1]);
}
int resu = 0;
for(int i = 0 ; i < len ; i++){
int cur = Math.min(left[i],right[i]);
cur = Math.max(0,cur - height[i]);
resu += cur;
}
return resu;
}
}