Leetcode 42.接雨水
分享一下自己关于这道题的思路,个人感觉更偏向初学者的思维。欢迎大家讨论。
问题描述
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
思路
1.判断该位置是否能够储水
每一个位置是否能储水取决于他左右两边是否存在比他更高的柱子。如果左右都存在高度比该位置高的柱子,那该位置就可以储水。因此只要能记录每一个位置的左右高度最大值,那么就可以根据高度大小来判断该位置是否可以储水。
2.判断该位置储水量
一个位置能否储水取决于他左右位置的最长柱子,那么储水量也当然与二者有关,且由其中的较短柱子决定,这也很好理解。但要注意的是要减掉该位置的长度,因为该位置的柱子也会占用储水的位置。因此一个位置的储水量=min(左边最大长度,右边最大长度)-该位置柱子长度。
步骤
1.找到最长的柱子,记录其位置下标及长度。以该下标为界,把数组分成两个部分。
2.对于左半边,每一个位置的右边最长柱子都是步骤1找到的那根柱子,因此每一个位置的右边高度最大值已知,只需要在从前往后遍历时动态更新左边高度最大值即可。此时,根据左右最大长度及每一个位置的柱子长度即可求得每一个位置的储水量。
3.对于右半边,每一个位置的左边最长柱子是步骤1找到的全局最长柱子,因此每一个位置的左边高度最大值已知。而要记录每一个位置的右边高度最大值,要注意是从后往前遍历,才可以动态更新每一个位置的右边高度最大值。此时,根据左右最大长度及每一个位置的柱子长度即可求得每一个位置的储水量。
4.把步骤2和步骤3的储水量相加即得到最终结果。
代码
public static int trap(int[] height) {
int maxIndex = 0; //全局最长柱子位置
int max = height[0]; //全局最长柱子长度
int cap = 0; //储水量
//求得最长柱子
for (int i = 1; i < height.length; i++) {
if(max < height[i]) {
max = height[i];
maxIndex = i;
}
}
int leftMax = height[0]; //左半边数组的左边最大长度
//遍历左半边数组
for (int i = 1; i < maxIndex; i++) {
if(leftMax < height[i]) {
leftMax = height[i]; //动态更新左边最大长度
}
/*对于左半边数组来说,每一个位置的柱子肯定短于右边最长柱子(全局最长柱子),
因此只要其小于左边最长柱子,就可以判断该位置可以储水。*/
if(height[i] < leftMax) {
cap += (leftMax - height[i]); //计算该位置的储水量
}
}
int rightMax = height[height.length - 1]; //右半边数组的右边最大长度
//遍历右半边数组
for (int j = height.length - 1; j > maxIndex; j--) {
if(rightMax < height[j]) {
rightMax = height[j]; //动态更新右边最大长度
}
/*与左半边数组类似,对于右半边数组来说,只要短于右边最长柱子就可以储水*/
if(height[j] < rightMax) {
cap += (rightMax - height[j]);
}
}
return cap;
}
思路仅供参考,抛砖引玉欢迎大家讨论。