「当青训营遇上码上掘金」主题四 - 攒青豆

47 阅读2分钟

当青训营遇上码上掘金

8.jpg

主题名称: 攒青豆

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

image.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

该题和LeetCode中接雨水题类似(leetcode.cn/problems/tr…)

方法一:暴力求解

该方法思路如下

  • 可以统计每个位置上的青豆数量
  • 各个位置的青豆数量为左右最高柱子中较小的减去该位置的柱子高度
  • 因为每到一个位置都要对左右两边进行一次遍历相当于循环嵌套了一层分析左右两边最高位置的循环,所以其复杂度是O(n^2)。

方法一:双指针法

该方法思路如下:在该方法中,定义一个左指针left初值为0,和一个右指针right初值为height.length - 1 , 并维护两个变量L_MAX和R_MAX分别代表左右两端的最高高度,初值均为0 ,不论左边还是右边,每一列的青豆数均为对应的(最高高度 - 当前高度), 进行累加, 当两指针相遇时即得到了青豆总数.

代码实现:

public class Main {
    public static void main(String[] args) {
        int[] height = { 5, 0, 2, 1, 4, 0, 1, 0, 3};
        int sum = calculate(height);
        System.out.println(sum);
    }
    public static int calculate(int[] height) {
        int res = 0;
        int left = 0;
        int right = height.length - 1;
        int L_MAX = 0;
        int R_MAX = 0;

        while (left < right) {
            if (height[left] < height[right]) {
                if (height[left] >= L_MAX) {
                    L_MAX = height[left];
                }
                res += L_MAX - height[left++];
            } else {
                if (height[right] >= R_MAX) {
                    R_MAX = height[right];
                }
                res += R_MAX - height[right--];
            }
        }
        return res;
    }
}