当青训营遇上码上掘金
思路解析
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
这道题很像 Leetcode 中的接雨水,下面是之前的自己的想法,参考了windliang的题解
一种最容易想到的就是只考虑单列的情况,求每一列的,我们只需要关注当前列,以及左边最高的墙,右边最高的墙就够了。至于可以装多少青豆,就看左最高墙和右最高墙的较小值了(木桶效应),所以可以分为三种情况:
较矮墙的高度大于当前列墙的高度
很明显,当前列可以装的青豆的大小就是较矮墙的高度,减去当前列的墙的高度即可。
较矮墙的高度小于当前列墙的高度
依旧很明显😁,当前列不能装哪怕一颗青豆。
较矮墙的高度等于当前列墙的高度
依旧很明显😁,和上一种情况一样,当前列不能装哪怕一颗青豆。
所以,只有较矮墙的高度大于当前列墙的高度时,才可以装青豆,装青豆的多少就是它们之间的差值
核心代码
public int trap(int[] height) {
int sum = 0, len = height.length;
// 最两端的列不用考虑,因为一定不会有青豆,所以下标从 1 到 len - 2
for (int i = 1; i < len - 1; i++) {
int left_max = 0, right_max = 0;
// 找出左边最高
for (int j = i - 1; j >= 0; j--) {
if (left_max < height[j]) {
left_max = height[j];
}
}
// 找出右边最高
for (int j = i + 1; j < len; j++) {
if (right_max < height[j]) {
right_max = height[j];
}
}
// 找出两端较小的
int min = Math.min(left_max, right_max);
// 只有较小的一段大于当前列的高度才会有青豆,其他情况不会有青豆
if (min > height[i]) {
sum += min - height[i];
}
}
return sum;
}
具体实现
import java.util.*;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int[] arr = {5,0,2,1,4,0,1,0,3};
System.out.println(trap(arr));// 17
}
public static int trap(int[] height) {
int sum = 0, len = height.length;
// 最两端的列不用考虑,因为一定不会有青豆,所以下标从 1 到 len - 2
for (int i = 1; i < len - 1; i++) {
int left_max = 0, right_max = 0;
// 找出左边最高
for (int j = i - 1; j >= 0; j--) {
if (left_max < height[j]) {
left_max = height[j];
}
}
// 找出右边最高
for (int j = i + 1; j < len; j++) {
if (right_max < height[j]) {
right_max = height[j];
}
}
// 找出两端较小的
int min = Math.min(left_max, right_max);
// 只有较小的一段大于当前列的高度才会有青豆,其他情况不会有青豆
if (min > height[i]) {
sum += min - height[i];
}
}
return sum;
}
}
显然,这种做法复杂度还是太高了,而且一直循环地找当前列的左极大值和右极大值,可以进行优化,就交给读者你们自己去探索了😋