一.题目要求
给定 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
1
1 <= n <=
2
∗
1
0
4
2 * 10^4
2∗104
0
0
0 <= height[i] <=
1
0
5
10^5
105
四.解题思路
解法1:没用双指针,能想到的就是按每一列对能存的水做计算,
某列存水量
v
a
l
u
e
=
m
i
n
(该列左边所有列的
m
a
x
,右边所有列的
m
a
x
)
−
该列高
h
e
i
g
h
t
某列存水量value=min(该列左边所有列的max,右边所有列的max)-该列高height
某列存水量value=min(该列左边所有列的max,右边所有列的max)−该列高height,由于从左往右遍历,左边最大值易得,但右侧最大值由于始终需要减少一个未知大小的值(即当前列高度),所以只能想到每次都判断的笨方法。
解法2:双指针。
计算公式和上面一样,对于每一列来说,都有其左右侧的maxLeft和maxRight,故对于左右指针Left和Right,也一样有左指针的LMaxLeft,LMaxRight和右指针的RMaxLeft和RMaxRight,若要求当前指针所指列的存水量value,(以左值针为例),我们可以很容易的求得左指针的LMaxLeft当前右指针的RMaxRight,但左指针的LMaxRight和右指针的RMaxLeft无法求出(因为没遍历到),但事实上,针对当前左指针所指列,我们无需求出LMaxRight,因为这时候会存在两种情况:
(1)LMaxLeft < RMaxRight
这种情况下,由计算公式,显然左指针所指的列有可能存水,我们有了LMaxLeft,还需求出LMaxRight,但此时RMaxRight > LMaxLeft,且根据坐标轴朝向,一定会有 LMaxRight >= RMaxRight,所以我们此时不需要考虑LMaxRight的值,它一定比RMaxRight要小,且又有LMaxLeft < RMaxRight,所以此时该列的可能存水量表达式一定为
v
a
l
u
e
=
L
M
a
x
L
e
f
t
−
c
u
r
r
e
n
t
H
e
i
g
h
t
value = LMaxLeft - currentHeight
value=LMaxLeft−currentHeight。而后该列判断完,将Left左移,同时更新LMaxLeft。
(2)LMaxLeft >= RMaxRight
表明右指针所指的列有可能存水,此时思路同上,
v
a
l
u
e
=
R
M
a
x
R
i
g
h
t
−
c
u
r
r
e
n
t
H
e
i
g
h
t
value = RMaxRight - currentHeight
value=RMaxRight−currentHeight。
五.代码实现
解法1
class Solution {
public:
int trap(vector<int>& height) {
int i,j;
int _trap=0;
int maxLeftH=height[0],maxRightH=-1;
for(i=0;i<height.size()-1;i++)
{
if(i==0||i==height.size()-1) continue;
int currentH=height[i];
//vector<int> tmp=height;
for(j=i+1;j<height.size();j++)
{
maxRightH=max(maxRightH,height[j]);
}
//sort(tmp.begin()+i+1,tmp.end());
//maxRightH=tmp[size(tmp)-1];
if(maxLeftH>currentH&&maxRightH>currentH)
{
_trap+=min(maxLeftH,maxRightH)-currentH;
}
maxLeftH=max(maxLeftH,currentH);
maxRightH=-1;
}
//1 1 2 1 1
return _trap;
}
};
解法2
class Solution {
public:
int trap(vector<int>& height) {
int i,j;
int _trap = 0;
int maxLeftH = height[0],maxRightH = height[size(height)-1];
for(i = 0, j = height.size()-1; i<j ;)
{
if(maxLeftH < maxRightH)
{
_trap += min(maxLeftH,maxRightH) - height[i];
i++;
maxLeftH = max(maxLeftH,height[i]);
}
else
{
_trap += min(maxLeftH,maxRightH) - height[j];
j--;
maxRightH = max(maxRightH,height[j]);
}
}
return _trap;
}
};
六.题目总结
解法还涉及到动态规划和栈,后续学到会补上。