当青训营遇上码上掘金
《攒青豆》题目描述
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
题目分析
看到题目,小伙伴们可能会比较懵而无从下手,但其实仔细理解题目后能够以简单易懂的方式解出该题。
该题目是想要求出能接住的青豆数,而直观地来看,就是找出那些《槽》,只有有槽的地方才能接住青豆;而给定一个位置i,如何判断它是不是在《槽》中的思路很简单,也即是以该位置为起始点,向左右两侧寻找比本位置高的柱子,高度分别为max_left,max_right;有如下几种情况:
- 左右两侧有一侧及以上都找不到比本位置高的柱子;即height[i]>=max_left || height[i]>=max_right
- 左右两侧柱子都比当前位置的柱子高,且左侧最高的柱子比右侧最高的柱子高;即height[i]<max_left && height[i]<max_right && max_left>max_right
- 左右两侧柱子都比当前位置的柱子高,且右侧最高的柱子比左侧最高的柱子高;即height[i]<max_left && height[i]<max_right && max_left<max_right
对于情况1,显然包含本位置柱子的《槽》不存在。
对于情况2,3。本位置柱子处于《槽》中,因此本位置能够接住Math.max(max_left, max_right)-height[i]的豆子。
上述过程是以位置i为起点,得到该位置能够接住的青豆数,因此题目所需计算的总的能接住的青豆数只需要遍历位置i累加青豆数即可。值得注意的是:最两端的柱子不用参与遍历,因为一定接不住豆子。因此遍历下标从 1 到 height.length-2。
代码
public int trap(int[] height) {
// 用于记录结果
int sum = 0;
// 最两端的柱子不用参与遍历,因为一定接不住豆子。因此遍历下标从 1 到 length - 2
for (int i = 1; i < height.length - 1; i++) {
// 以height[i]为中心寻找左右两侧最高的柱子以形成【坑】
int max_left = 0;
//找出左边最高的柱子
for (int j = i - 1; j >= 0; j--) {
if (height[j] > max_left) {
max_left = height[j];
}
}
int max_right = 0;
//找出右边最高的柱子
for (int j = i + 1; j < height.length; j++) {
if (height[j] > max_right) {
max_right = height[j];
}
}
//找出两端较小的柱子以计算能够接住的豆子
int min = Math.min(max_left, max_right);
//只有当较小的最高的柱子大于当前柱子的高度才能接住豆子【因为必须形成【坑】】
if (min > height[i]) {
sum = sum + (min - height[i]);
}
}
return sum;
}