当青训营遇上码上掘金-攒青豆

106 阅读2分钟

当青训营遇上码上掘金

题目

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

题目分析

计算能够借助的豆子数量,实际上就是计算每一列的高度和总列数。

可以分为以下几种情况:

仅有边界两个柱子

image.png

豆子的高度仍然取决于两个柱子中较短的柱子

列数为1列

除去边界柱子,内部仅有小于二者的柱子

image.png

豆子的高度仍然取决于两个柱子中较短的柱子,计算时,每一列只需要用较短的边界柱子的高度减去该列内部柱子的高度即可。

列数为给出的数组长度 - 2

内部有高于边界柱子的柱子

image.png

如图,C柱高于E柱,而内部一旦有高于边界柱子的柱子,就会将青豆计算区域划分为两部分,相当于新的边界柱子。

左半部分豆子的高度为 A柱与C柱中短的那个,也就是C柱的高度 减去 内部柱B的高度。

右半部分豆子的高度为 C柱与E柱中短的那个,也就是E柱的高度 减去 内部柱D的高度。

总结

所以,设计算法时,可以从边界柱中较短的柱子出发,计算内部能容纳的青豆数量。

一旦遇到比边界柱高的内部柱,就设该柱为新的边界柱,并比较与另一个边界柱子的高度,从二者中小的柱子出发,计算内部容乃的青豆数量。

直到两个边界柱相遇算法结束,或者遇到比当前柱子更高的内部柱,回到上一步,继续进行。

算法实现


/**
* 支持 import Java 标准库 (JDK 1.8)
*/
import java.util.*;

/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
   public static void main(String []args) {
      int[] nums = new int[] {5, 0, 2, 1, 4, 0, 1, 0, 3};
      System.out.println(fun(nums));
   }

   public static int fun(int[] nums) {
      int sum = 0;
      int l = 0;
      int r = nums.length - 1;
      int lBorder = nums[l];
      int rBorder = nums[r];
      while(l < r) {
        if (lBorder <= rBorder) {
            while (nums[l] <= lBorder && l < r) {
                sum += lBorder - nums[l];
                l++;
            }
            lBorder = nums[l];
        } else {
            while (nums[r] <= rBorder && l < r) {
                sum += rBorder - nums[r];
                r--;
            }
            rBorder = nums[r];
        }
      }
      return sum;

   }

}