当青训营遇上码上掘金——主题4——攒青豆(Java实现)

199 阅读1分钟

当青训营遇上马上掘金!

题目描述

现有 nn 个宽度为 11 的柱子,给出 nn 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

a3f04d7089324636baf9ddc7630c36a5_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.webp

样例

输入:

heights=[5,0,2,1,4,0,1,0,3]heights = [5, 0, 2, 1, 4, 0, 1, 0, 3]

输出:

1717

解释:

可见上方图片展示,最多可以盛放 1717 单位的青豆。

题目解答

题目原型

实际上本题目在LeetCode上可以看到类似题目——接雨水,原题是接水,本题是接青豆。

思路求解

我们可以把两个高度中间的地方,看作一个桶,一个桶能不能装青豆,能装多少青豆,取决于这个地方左右两侧的高度的较小者,以及这个地方的高度,两者的差值就是能装青豆的数量。为了获得这三个元素,由于每个地方的高度我们已经知道,我们可以前缀后缀取得最大值,然后两者之间的较小的那个,就是我们的边界,然后减去当前高度即可。

复杂度分析

我们需要分别要求前缀最大值、后缀最大值、接青豆数量,需要遍历数组三次,因此时间复杂度为O(n)O(n)

我们需要前缀、后缀数组来存储最大值,因此空间复杂度是 O(n)O(n)

代码实现

 public class Main {
     public static void main(String[] args) {
         int[] heights = {5, 0, 2, 1, 4, 0, 1, 0, 3};
         System.out.println(trap(heights));
     }
 ​
     public static int trap(int[] height) {
         int n = height.length;
         int res = 0;
         int[] preMax = new int[n], sufMax = new int[n];
         preMax[0] = height[0];
         sufMax[n - 1] = height[n - 1];
         for (int i = 1; i < n; i++) preMax[i] = Math.max(preMax[i - 1], height[i]);
         for (int i = n - 2; i >= 0; i--) sufMax[i] = Math.max(sufMax[i + 1], height[i]);
         for (int i = 0; i < n; i++) res += (Math.min(preMax[i], sufMax[i]) - height[i]);
         return res;
     }
 }