【青训营X码上掘金】主题创作活动--主题四:攒青豆
当青训营遇上码上掘金
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 个单位的青豆。
2、创作思路
-
思路一:暴力遍历法
思路一较为简单。我们可以依次遍历表示柱子高度的数组,每当我们读到一个高度时,找到该柱子左右两边的最高值,然后取左右两边最高值间更小的那个,再减去当前柱子高度,就是该空间可以攒下的青豆。
注意:我们只需要从第二个元素开始遍历,因为第一个柱子不可能攒下青豆,最后一个柱子同理。
样例分析:
- 第一个读到的柱子高度为0,此时它左边柱子最高值为5,右边柱子最高值为4,取两者更小值4,当前空间攒下的青豆为4-0=4青豆。
- 第二个读到的柱子高度为2,此时它左边柱子最高值为5,右边柱子最高值为4,取两者更小值4,当前空间攒下的青豆为4-2=2青豆。
- ......
- 最后将青豆累加,得到最终结果17。
-
思路二:双指针遍历法
双指针即从数组左右两边向中间遍历,可以降低时间复杂度。
双指针主要思路如下:
- 第一步:记录左右两边柱子的最大高度。
- 第二步:定义双指针由数组两边向中间遍历。
- 第三步:如果双指针对应的数组的值大于最大高度,替换最大高度;然后计算当前空间青豆数。
- 第四步:当双指针指向同一位置时,得到最终结果。
3、代码实现
-
思路一
//暴力遍历法 public static int getGreenBean1(int[] nums){ int tmp = 0; int res = 0; for (int i = 1;i < nums.length;i++){ tmp = getLeftMax(i,nums) < getRightMax(i,nums) ? getLeftMax(i,nums) : getRightMax(i,nums); res += tmp - nums[i]; } return res; } public static int getLeftMax(int index,int[] nums){ int res = 0; for (int i = index;i >= 0;i--){ if (nums[i] > res) res = nums[i]; } return res; } public static int getRightMax(int index,int[] nums){ int res = 0; for (int i = index;i < nums.length;i++){ if (nums[i] > res) res = nums[i]; } return res; } -
思路二
//双指针遍历法 public static int getGreenBean2(int[] nums){ int res = 0; int left = 0; int right = nums.length - 1; int leftMax = 0; int rightMax = 0; while (left < right){ if (nums[left] < nums[right]){ if (nums[left] > leftMax) leftMax = nums[left]; res += leftMax - nums[left++]; }else { if (nums[right] > rightMax) rightMax = nums[right]; res += rightMax - nums[right--]; } } return res; }
完整代码见码上掘金:
4、对比分析
-
时间复杂度
暴力遍历法每读到一个高度,都要遍历数组找到左右两边的最大高度;而双指针遍历则不用,只需要遍历一遍整个数组即可得出结果。双指针遍历法的时间复杂度是远远小于暴力遍历法的。
-
空间复杂度
双指针需要创建的临时变量比较多,而暴力遍历法的临时变量只有一个。所以暴力遍历法的空间复杂度优于双指针遍历法。
-
总结
本次主题创作主要是涉及数组的相关知识,以上解法都是比较浅显的解法。如果大家有更好的解法,我也会认真学习。同时,也欢迎大家阅读,以及提出宝贵意见。