当青训营遇上码上掘金
题目描述
现有 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(大小写敏感)
*青训营 X 码上掘金主题4攒青豆--双指针解法
*/
public class Main {
public static void main(String []args) {
int[] height = { 5, 0, 2, 1, 4, 0, 1, 0, 3};
int total = SaveBean(height);
System.out.println(total);
}
public static int SaveBean(int[] height) {
int total = 0;
int left = 0;
int right = height.length - 1;
int leftMax = 0;
int rightMax = 0;
//循环不变量:left < right
while (left < right) {
//左指针右移,右指针左移,更新当前leftMax和rightMax
leftMax = Math.max(leftMax, height[left]);
rightMax = Math.max(rightMax, height[right]);
if (height[left] < height[right]) {
//height[left] < height[right],则必有leftMax < rightMax
total = total + leftMax - height[left];
left++;
} else {
//height[left] > height[right],则必有leftMax > rightMax
total = total + rightMax - height[right];
right--;
}
}
return total;
}
}
代码已发布:码上掘金攒青豆代码链接