给定 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 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5] 输出:9
提示:
n == height.length
1 <= n <= 2 * 10^4
0 <= height[i] <= 10^5
思路:
黑色的看成墙,蓝色的看成水,宽度一样,给定一个数组,每个数代表从左到右墙的高度,求出能装多少单位的水。也就是图中蓝色正方形的个数。
解法一:按行求
这是我最开始想到的一个解法,提交后直接 AC 了,自己都震惊了。就是先求高度为 1的水,再求高度为 2的水,再求高度为 3的水。
整个思路就是,求第 i 层的水,遍历每个位置,如果当前的高度小于 i,并且两边有高度大于等于 i 的,说明这个地方一定有水,水就可以加 1。
如果求高度为 i 的水,首先用一个变量 temp 保存当前累积的水,初始化为 0。从左到右遍历墙的高度,遇到高度大于等于 i 的时候,开始更新 temp。更新原则是遇到高度小于 i 的就把 temp 加 1,遇到高度大于等于 i 的,就把 temp 加到最终的答案 ans 里,并且 temp 置零,然后继续循环。
我们就以题目的例子讲一下。
先求第 1行的水。
image.png {:align=center}
也就是红色区域中的水,数组是 height = [ 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 ] 。
原则是高度小于 1,temp ++,高度大于等于 1,ans = ans + temp,temp = 0。
temp 初始化为 0,ans = 0
height[0] 等于 0 < 1,不更新。
height[1] 等于 1 >= 1,开始更新 temp。
height[2] 等于 0 < 1,temp = temp + 1 = 1。
height[3] 等于 2 >= 1,ans = ans + temp = 1,temp = 0。
height[4] 等于 1 >= 1,ans = ans + temp = 1,temp = 0。
height[5] 等于 0 < 1,temp = temp + 1 = 1。
height[6] 等于 1 >= 1,ans = ans + temp = 2,temp = 0。
剩下的 height[7] 到最后,高度都大于等于 1,更新 ans = ans + temp = 2,temp = 0。而其实 temp 一直都是 0,所以 ans 没有变化。
再求第 2 行的水。
image.png {:align=center}
也就是红色区域中的水,数组是 height = [ 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 ]。
原则是高度小于 2,temp ++,高度大于等于 2,ans = ans + temp,temp = 0。
temp 初始化为 0,ans 此时等于 2。
height[0] 等于 0 < 2,不更新。
height[1] 等于 1 < 2,不更新。
height[2] 等于 0 < 2,不更新。
height[3] 等于 2 >= 2,开始更新
height[4] 等于 1 < 2,temp = temp + 1 = 1。
height[5] 等于 0 < 2,temp = temp + 1 = 2。
height[6] 等于 1 < 2,temp = temp + 1 = 3。
height[7] 等于 3 >= 2,ans = ans + temp = 5,temp = 0。
height[8] 等于 2 >= 2,ans = ans + temp = 3,temp = 0。
height[9] 等于 1 < 2,temp = temp + 1 = 1。
height[10] 等于 2 >= 2,ans = ans + temp = 6,temp = 0。
height[11] 等于 1 < 2,temp = temp + 1 = 1。
然后结束循环,此时的 ans 就是6。
再看第 3 层。
image.png {:align=center}
按照之前的算法,之前的都是小于 3 的,不更新 temp,然后到 height[7] 等于 3,开始更新 temp,但是后边没有 height 大于等于 3 了,所以 ans 没有更新。
代码:
class Solution {
public:
int trap(vector& height) {
int sum = 0;
int max = getMax(height); //找到最大的高度以便遍历
for(int i = 1; i < max; i++){
bool isStart = false; //标记是否开始更新temp
int temp_sum = 0;
for(int j = 0; j < height.size(); j++){
if(isStart && height[j] < i){
temp_sum++;
}
if(height[j] >= i){
sum += temp_sum;
temp_sum = 0;
isStart = true;
}
}
}
return sum;
}
int getMax(vector& height){
int max = 0;
for(int i = 0; i < height.size(); i++){
if(height[i] > max){
max = height[i];
}
}
return max;
}
};