题目:
Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.
给定n个非负整数代表一个图,每个栏的宽度为1,计算下雨后,它能盛多少水。
For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1]
, return 6
.
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!
思路:
从图中可以看出每个点 i 处的雨水量为 i 左半边高度的最大值和右半边高度的最大值中间较小的 - 当前 i 的高度,假设当前 i 处的高度小于前面两者。比如说图中的第5个的雨水量是左边的最高点即第四个(2)和右边的最高点第八个(3)中较低的 2 ,然后减去当前高度 (1)得到当前点的雨水量 1。因此只要知道当前点前半段的最高点和后半段的最高点即可。
对于每个柱子,找到其左右两边最高的柱子,所以,
1. 从左往右扫描一遍,对于每个柱子,求取左边最大值;
2. 从右往左扫描一遍,对于每个柱子,求最大右值;
3. 再扫描一遍,把每个柱子的面积并累加。
也可以,
1. 扫描一遍,找到最高的柱子,这个柱子将数组分为两半;
2. 处理左边一半;
3. 处理右边一半。
代码1:
class Solution {
public:
int trap(vector<int>& height)
{
int result = 0;
int len = height.size();
if(len <= 1)
return 0;
vector<int> f(len , 0);//保存左边的
vector<int> g(len , 0);//保存右边的
for(int i = 1 ; i < len ; i++)
{
f[i] = max(f[i-1] , height[i-1]);
g[len-1-i] = max(g[len-i] , height[len-i]);
}
int tmp = 0;
for(int i = 0 ; i < len ; i++)
{
tmp = min(f[i] , g[i]);
//只有左边和右边的较小值 > 当前高度才有雨水
if(tmp > height[i])
result += (tmp - height[i]);
}
return result;
}
};
代码2:
class Solution {
public:
int trap(vector<int>& height)
{
int result = 0;
int len = height.size();
if(len <= 1)
return 0;
int maxPos = 0;
int max = height[0];
//找出最高点所在位置
for(int i = 1 ; i < len ; i++)
{
if(height[i] >= max)
{
maxPos = i;
max = height[i];
}
}
//求左半边雨水
int leftPeak = 0;
for(int i = 0 ; i < maxPos ; i++)
{
if(height[i] >= leftPeak)
leftPeak = height[i];
else
result += (leftPeak - height[i]);
}
//求右半边雨水
int rightPeak = 0;
for(int j = len - 1 ; j > maxPos ; j--)
{
if(height[j] >= rightPeak)
rightPeak = height[j];
else
result += (rightPeak - height[j]);
}
return result;
}
};