当青训营遇上码上掘金
题目
主题 4:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入: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、根据以上3点可以编写代码:
-
- 先确认边界,分别是“第一个不是值不是0的下标”、“最后一个值不是0的下标”、“最高点的值”、“最高点的下标”
// 寻找第一个不是值不是0的下标
int first_not_zore = -1;
// 寻找最后一个值不是0的下标
int end_not_zore = -1;
// 寻找最高点的值
int max_height = 0;
// 寻找最高点的下标
int max_height_index = 0;
// 根据height[],为上述4个变量赋值
for(int i=0; i<height.length; i++){
if(first_not_zore == -1 && height[i] != 0){
first_not_zore = i;
}
if(max_height < height[i]){
max_height = height[i];
max_height_index = i;
}
if(height[i] != 0) {
end_not_zore = i;
}
}
-
- 如果全部柱子都为零,则无需再计算了。
// 若height[] 全部为零
if(first_not_zore == -1 ) return 0;
-
- 最后分两部分计算结果,开始(第一个不为零的柱子)-最高、最高-结束(最后一个不为零的柱子)
// 最终可以接的res个单位的青豆
int res = 0;
// 将数组根据max_height_index划分为两部分,第一部分 first_not_zore ~ max_height_index
int temp = first_not_zore;
for(int i=first_not_zore; i<=max_height_index; i++){
if( height[i] >= height[temp] ){
for(int j=temp+1; j<i; j++){
res += (height[temp] - height[j]);
}
temp = i;
}
}
// 将数组根据max_height_index划分为两部分,第二部分 max_height_index ~ end_not_zore
temp = end_not_zore;
for(int i=end_not_zore; i>=max_height_index; i--){
if( height[i] >= height[temp] ){
for(int j=temp-1; j>i; j--){
res += (height[temp] - height[j]);
}
temp = i;
}
}
return res;
5、完整代码如下: