攒青豆|「青训营 X 码上掘金」
当青训营遇上码上掘金。
主题展示
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
题目分析
首先,青豆的总单位数等于各柱子所在位置能积攒的青豆高度的总和。已知输入为柱子高度的数组,height[n],柱子数量为n,用数组表示这一列柱子上青豆的高度:peaHeight[n]。
通过例子思考青豆高度的规律。先按照从左到右的顺序将柱子编号为0-9。选取柱1作为对象来分析,height[1] = 0, 青豆的高度是4。从柱1为中心向左扫描,最高为柱0,height[0] = 5, 而向右边扫描,会发现最高为柱4,height[4] = 4,而青豆的高度则为min(height[1], height[4])。针对这种规律,我的理解如下:
首先能装青豆的前提是,目标柱两边,分别能存在严格高于该目标的柱。决定装青豆的高度,先假设找到满足上述要求的柱,任意两个在两边的柱都能组成一个“桶”,而桶能装青豆的高度为构成桶的最短柱子。则青豆的高度一般为:构成桶的最短柱高度-目标柱的高度。
而倒入足量的青豆,会导致所有柱子所在位置都被尽可能填满,所以每个位置青豆的高度都是使得目标柱青豆高度最高的桶构造成的。而最高的“桶”,不难得出,是左右两边最高的柱构成。也即假设目标柱编号为i,则通过正向遍历height[i],可以更新每个位置左端最高的柱子并记录为left[i] = max(height[0:i]),反向遍历可以更新每个位置右端最高柱子记录right[i] = max(height[i+1: n])。每个位置对应桶高度:
bucket[i] =min(left[i], right[i])那么peaHeight[i]= bucket[i]-height[i],对peaHeight求和即为最终结果。
代码展示
*/
import java.util.*;
public class Main {
public static void main(String []args) {
int[] height = {5,0,2,1,4,0,1,0,3};
int n = height.length;
int[] left = new int[n];
int[] right = new int[n];
int[] bucket=new int[n];
int sum = 0;
int maxnum = 0;
for (int i = 0; i < n; i++) {
left[i] = Math.max(maxnum, height[i]);
maxnum = left[i];
}
maxnum = 0;
for (int i = n - 1; i >= 0; i--) {
right[i] = Math.max(maxnum, height[i]);
maxnum = right[i];
}
for (int i = 0; i < n; i++) {
bucket[i] = Math.min(right[i], left[i]);
sum += Math.max(0, bucket[i] - height[i]);
}
System.out.println(sum);
}
}