题目:给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
思路:通过left和right双指针表示接水容器的左右两个柱子。将遍历到的第一个大于0的数,作为容器的左边框,用left_flag判断是否已有左边框。如果不满足左边框的条件,则判断能否成为右边框,判断条件:1、左边框要存在,右边框不存在。2、右边框要大于等于左边框。如果左右边框都已找到,则计算装了多少水。
总结:在编写代码的时候需要考虑一种情况:当左边框已经找到的情况下,之后的柱子都比左边框短,这样根据上面的思路就无法找到一个容器。所以需要根据left是不是已经指向最后一个柱子来判断是否已经遍历完。当出现这种情况时,需要在left右边找到最大的柱子,并判断最大的柱子是否跟left相邻。如果相邻则将left有移一位,如果不是相邻则与left组成容器并计算装了多少水。依次循环至left指向最后一个柱子。
public int trap(int[] heights) {
int result = 0;
int left = 0, right = 0;
boolean left_flag = false , right_flag = false;
for (int i = 0; i < heights.length; i++) {
//将遍历到的第一个大于0的数,作为容器的左边框,用left_flag判断是否已有左边框
if(heights[i] > 0 && !left_flag) {
left = i;
left_flag = true;
}
/*
* 如果不满足左边框的条件,则判断能否成为右边框,判断条件:
* 1、左边框要存在,右边框不存在
* 2、右边框要大于等于左边框
*/
else if (heights[i] > 0 && left_flag && !right_flag && heights[i] >= heights[left] ){
right = i;
right_flag = true;
}
//如果左右边框都找到了,则计算装了多少水
if (right_flag && left_flag){
int h = heights[left] > heights[right]?heights[right]:heights[left]; //两个边框选最低的
int w = right - left + 1; //计算宽度
int sum = h * w; //计算一个有几个单位
//for循环计算除了边框装了多少单位的水
for (int j = left + 1; j <= right - 1 ; j++) {
sum -= heights[j];
}
//除去边框
sum -= 2 * h;
result += sum;
left = right; //将右边框作为新容器的左边框
right_flag =false;
}
//当遍历到了最后一个,但是左边框还没到最后,则说明有可能漏了
if (i == heights.length -1 && left < i){
int max = heights[left + 1];
int max_index = left + 1;
//找到除了left最大的
for (int j = left + 2; j < heights.length ; j++) {
if (heights[j] > max) {
max = heights[j];
max_index = j;
}
}
//如果最大的就是之前left的下一个,则将left右移一个。因为到这了说明后面的点没有比之前的left更小的。
//重置left后,将i也重置,然后重新按上面的逻辑寻找容器
if (max_index - left == 1){
left++;
i = left;
}else{
//如果最大的不是left的下一个,则次最大(max_index)和left构成的容器也可以装水,计算其中的水量
int new_sum = (max_index - left + 1) * max;
for (int k = left + 1; k <= max_index - 1 ; k++) {
new_sum -= heights[k];
}
new_sum -= 2 * max;
result += new_sum;
left = max_index; //将left移动到次大的index
i = left; // 将i重置,继续用上面的逻辑判断后面还有没有容器
}
}
}
return result;
}