当青训营遇上码上掘金
题目——攒青豆
题目描述
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
测试样例
测试样例:
输入:inputs = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
思路分析
对于这道题目的解题思路,可以从双指针入手:
我们可以假设输入数据中所输入的柱子高度的数量为N,输入数据存储到inputs数组中。
在双指针解法里,无需创建额外空间来辅助计算,因此该方法的空间复杂度为,具体算法描述如下:
- 输入柱子高度的数组
pillarHeights - 首先设置代表数组下标的指针
lCount,该指针的值从数组下标最左边开始,初始化为0;然后设置下标指针rCount,该指针值从数组下标最右边开始。 - 设置记录左右边的最大值变量
lMax、rMax并设置初值为0。 - 通过一个循环不断更新两个指针的位置,指针
lCount向数组下标的右边前进(len-1的方向),而指针rCount向数组下标的左边前进(0的方向)。 - 在两个指针移动时,不断用柱子高度比较当前最大值变量
lMax、rMax并计算最大值与相遇的柱子的高度差记录到能接住的青豆数的结果中。 - 当两个指针相遇时,循环终止,返回得到当前输入柱子高度情况下,能接住的最多青豆数。
由于主方法只需要经过一次while循环,双指针lCount及rCount在循环中以“两端夹”式的朝中遍历,过程中不断更新能接住的最大数量beans,只需不到N次执行便可求出答案,因此在双指针相遇时即可求出能够接住青豆的最大数量beans,分析此种方法的时间复杂度只有。
代码
public class Main {
public static void main(String[] args) {
// 输入测试样例
int[] inputs = {5, 0, 2, 1, 4, 0, 1, 0, 3};
System.out.println(connectBeans(inputs));
}
public static int connectBeans(int[] pillarHeights) {
final int pillarNumber = (pillarHeights.length - 1);
int beans = 0;
int lMax = 0, rMax = 0;
int lCount = 0, rCount = pillarNumber;
while (true) {
if (lCount > rCount) break;
if (lMax <= rMax) {
if (lMax < pillarHeights[lCount]) lMax = pillarHeights[lCount];
int numTmp = lMax - pillarHeights[lCount];
beans = beans + numTmp;
lCount++;
} else {
if (rMax < pillarHeights[rCount]) rMax = pillarHeights[rCount];
int numTmp = rMax - pillarHeights[rCount];
beans = beans + numTmp;
rCount--;
}
}
return beans;
}
}