当青训营遇上码上掘金
注:用的java,三重for循环实现,没用到指针,只是谈一个思路,并没涉及什么算法
介绍
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
思路
我的想法是就像水杯装水一样,得两侧都有杯壁水才不会漏
同理,如果将这个想象成一个一个的小格子,然后每个青豆格的左右延伸出去必定有柱子格(想象不出可以看下图)
那我们就可以这样做:
- 先找到所给数组的最大值以及数组长度
- 横向循环遍历,循环内部竖向遍历,竖向遍历再内部横向遍历(原理见下图)
- 每次遍历到有青豆的格子就直接开始遍历下一列,因为是从上往下遍历,所以只要上面有青豆就说明这一列的下面都有青豆
- 最后遍历结束就可以计算总共的青豆数量了
实现
- 找到所给数组的最大值以及数组长度
int[] height = new int[]{5, 0, 2, 1, 4, 0, 1, 0, 3}; // 定义高度
int maxHeight = Arrays.stream(height).max().getAsInt(); // 数组的最大值
int maxWidth = height.length; // 数组长度
int beans = 0; // 青豆数量
- 横向遍历
for (int x = 0; x < maxWidth; x++) {
// 高度为1或2时直接结束,青豆数量为0
if (maxWidth < 3) {
break;
}
// 排除第一列和最后一列
if (x == 0 || x == maxWidth - 1) {
continue;
}
/* 此处为竖向从上往下遍历的代码 */
}
- 竖向遍历,内部横向遍历
for (int y = maxHeight; y > height[x]; y--) {
boolean left = false; // 用于保留左边对比的结果
// 横向遍历
for (int x2 = 0; x2 < maxWidth; x2++) {
// 左边对比
if (x2 < x) {
if (height[x2] >= y) {
left = true;
x2 = x; // 使x2=x,使for循环x2++后可以跳过后续左边多余的对比
}
continue;
}
// 等于
if (x2 == x) continue;
// 右边,只有 x2>x 时才会运行到这里
if (left && height[x2] >= y) {
// 因为是从上往下遍历,所以上面有青豆说明这一列下面也会有,数量为 y-height[x]
beans += y - height[x]; // 加上这一列的青豆数量
y = height[x]; // 加好之后,这一列不需要竖向继续往下遍历了
break;
}
}
}
- 最后输出青豆数量
System.out.println(beans); // 打印青豆数量
完整代码: 攒青豆 - 码上掘金 (juejin.cn)