当青训营遇上码上掘金
题目
主题 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 个单位的青豆。
分析解决思路
本题目的关键点就在于在两根柱子之间的凹槽才能存豆子。
我们需要用双指针遍历柱子(一左一右指针,分别指向两边的柱子)。因为有凹槽,所以肯定是低柱子接的青豆为主,低柱子在往左或往右移(注:因为低柱子和高柱子的左右情况不一样,可能是低柱子在左、这时候就是往右移。也可能高柱子在左,这时候低柱子要往左移。)在移动时要比较旁边柱子是否比该柱子高,如果比这颗柱子高就要记录下来(因为这时能接到的豆子就因为高度的变化上限得到了提升。)然后按照这个过程以此类推,当左右指针指向的柱子是同一个时,就要结束循环。
注:在比较低柱子与旁边柱子的大小时,如果旁边的柱子比它低,就表明肯定有凹槽,并且不管下一个柱子高低,青豆的数量都会是:低柱子-旁边柱子 的单位。如果旁边的旁边柱子还没有它高,那就原来的青豆在加上:低柱子-旁边的旁边柱子。知道低柱子的遇到比它高的柱子时,说明一个凹槽结束,这就要将低柱子换成比它高的那个柱子在继续寻找凹槽。
就是一个双指针问题。
代码
/**
* 支持 import Java 标准库 (JDK 1.8)
*/
import java.util.*;
/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
public static void main(String []args) {
int[] heights={5,0,2,1,4,0,1,0,3};
System.out.println(Solve(heights));
}
public static int Solve(int[] heights) {
//左指针
int left = 0;
//右指针
int right = heights.length - 1;
int max_l = 0;
int max_r = 0;
int sum = 0;
//两指针分别从左、右向中间遍历
while (left != right) {
//右边柱子高,就以左边短柱子接到的豆子
//第一遍:left=5,right=3,max_r=3,sum=3
//第二遍: left=5,right=0,max_r=3,sum=5
//...
//找左右柱子小的下一个凹槽加起来
if (heights[left] < heights[right]) {
if (heights[left] >= max_l) {
max_l = heights[left];
}
sum += max_l - heights[left++];
}
if (heights[right] >= max_r) {
max_r = heights[right];
}
sum += max_r - heights[right--];
}
return sum;
}
}