先上代码
/**
* 支持 import Java 标准库 (JDK 1.8)
*/
import java.util.*;
/**
* 注意:目前 Java 代码的入口类名称必须为 Main(大小写敏感)
*/
public class Main {
public static void main(String[] args) {
int[] height = {5, 0, 2, 1, 4, 0, 1, 0, 3};
//int[] height = {0, 3,0,2,5,4};
int beans = gatherGreenBeans(height, 0, height.length - 1);
System.out.println(beans);
}
private static int gatherGreenBeans(int[] height, int left, int right) {
//左边最高柱子和右边最高柱子
int leftHighest = 0, rightHighest = 0;
//可接住的青豆数
int beans = 0;
//从左边或者右边找到非零的最低的那颗柱子并进行相应计算
while (left < right) {
if (height[left] > height[right]) {
rightHighest = Math.max(height[right], rightHighest);
beans += rightHighest - height[right];
right--;
} else {
leftHighest = Math.max(height[left], leftHighest);
beans += leftHighest - height[left];
left++;
}
}
return beans;
}
}
- 观察问题
看到攒青豆问题,我首先想到的是可以攒青豆的有哪些地方?根据观察,我们可以发现,当柱子之间有空隙时就可以积攒青豆,具体的,当一个柱子的高度小于它左右两边的高度时,就有可能在这个柱子上面攒青豆,例如有[2,1,2]的柱子,这时我们可以在高度为1的柱子上面攒青豆 - 如何实现
我们需要先找到这些可以积攒青豆的柱子,进行相应计算得到青豆的数量.在这里,我用到的是双指针法解决攒青豆的问题. - 具体实现
- 具体的,我们可以定义两个指针
left和right,一个指向数组的左端点,一个指向数组的右端点,逐步向中间遍历找到可以积攒豆子的柱子 - 每次比较
left和right指针所指向柱子的高度,如果左边的柱子高度大于右边柱子高度,则我们可以从右向左找可以积攒豆子的柱子,我们用rightHighest代表已经遍历的右边柱子的最高高度,并通过比较right所指向柱子的高度和rightHighest的值更新rightHighest的值,在更新完rightHighest之后,如果right所指向柱子的高度小于rightHighest,则该柱子可以积攒青豆rightHighest-height[right]个,将这个数加到beans上并将右指针向左移动. - 类似的,如果右边柱子高度小于左边柱子高度,则我们可以从左向右找可以积攒豆子的柱子,我们用
leftHighest代表以及遍历的左边柱子的最高高度,并通过比较left所指向柱子的高度和leftHighest的值更新leftHighest的值,在更新完leftHighest之后,如果left所指向柱子的高度小于leftHighest,则该柱子可以积攒青豆leftHighest-height[left]个,将这个数加到beans上并将右指针向右移动. - 不断重复上述步骤,直至
left>right,此时,beans的数值即为我们所求的青豆数.