青训营 X 码上掘金 | 攒青豆

51 阅读1分钟

当青训营遇上码上掘金

image.png

  • 主题 4:攒青豆

    现有 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 个单位的青豆。

思路

根据图片可以知道接住青豆的多少取决于两侧栏杆的高度。

解析

看见攒青豆问题,脑子立马想起接雨水问题,有四种方法可以接雨水,那我也有四种方法可以攒青豆。四种方法分别是:动态规划双指针线性扫描。我自己使用双指针的,但最为巧妙的方法,还得属栈。下面我只介绍双指针这一种方法。

采用双指针法,从两端向中间遍历。

该方法思路如下:

  1. 先定义两个变量来记录左右两端的最大值。
  2. 从左右两端向中间遍历。
  3. 如果左右指针指向的值大于对应的最大值,则更新最大值为当前值。
  4. 否则,计算青豆数量。
  5. 当左右两个指针为同一位置时,结束循环

代码

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[] arr) {
        int L = 0;
        int R = arr.length - 1;
        int MAX_L = 0;
        int MAX_R = 0;
        int sum = 0;
        while (L < R) {
            if (arr[L] < arr[R]) {
                if (arr[L] >= MAX_L) {
                    MAX_L = arr[L];
                }
                sum += MAX_L - arr[L++];
            } else {
                if (arr[R] >= MAX_R) {
                    MAX_R = arr[R];
                }
                sum += MAX_R - arr[R--];
            }
        }
        return sum;
    }
}