题目
给定
n
个非负整数表示每个宽度为1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例
提示
n == height.length
1 <= n <= 2 * 104
0 <= height[i] <= 105
原题链接
思路
我们发现对于
i
位置能达到的水柱高度取决于左边最高柱子和右边最高柱子;
我们暂且
记左边最高柱子为lmax
;
记右边最高柱子为rmax
;
倘若i
位置没有黑色柱子的话,那么i
位置的水柱最高高度为min(lmax, rmax)
若考虑到黑色柱子的话,那么对于i
位置来说其能接的雨水为
rain[i] = min(lmax, rmax) - height[i]
其中height[i] = 0
暴力
class Solution
{
public:
int trap(vector<int>& height)
{
int n = height.size();
int res = 0;
for(int i = 1; i < n - 1; i++)
{
int lmax = 0, rmax = 0;
for(int j = i; j >= 0; j--) lmax = max(lmax, height[j]);//找左边最高柱子
for(int j = i; j < n; j++) rmax = max(rmax, height[j]);//找右边最高柱子
res += min(lmax, rmax) - height[i];
}
return res;
}
};
好好好超时了
优化
将第一次计算的i
位置左右的最高柱子全部记录下来,开两个vector,用空间换时间;
class Solution
{
public:
int trap(vector<int>& height)
{
int n = height.size();
int res = 0;
vector<int> lmax(n), rmax(n);
lmax[0] = height[0];
rmax[n - 1] = height[n - 1];
for(int i = 1; i < n; i++) lmax[i] = max(lmax[i - 1], height[i]);
for(int i = n - 2; i >= 0; i--) rmax[i] = max(rmax[i + 1], height[i]);
for(int i = 1; i < n - 1; i++)
res += min(lmax[i], rmax[i]) - height[i];
return res;
}
};
双指针
思路和上面基本一样,只不过上面保存了
i
位置左右的做高柱子高度;
而下面思路计算到i
的时候,之间计算i
位置可以接雨水的高度,又在上面的基础上减少了空间复杂度
此时的 lmax 是 left 指针左边的最高柱子,但是 rmax 并不一定是 left 指针右边最高的柱子
对于lmax < rmax,其实我们只关心min(lmax, rmax)
,rmax是否为最大我们并不关心,因为接水只与最低的一边有关。那么我们看代码:
class Solution
{
public:
int trap(vector<int>& height)
{
if (height.empty()) return 0;
int n = height.size();
int left = 0, right = n - 1;
int res = 0;
int lmax = height[0];
int rmax = height[n - 1];
while (left <= right)
{
lmax = max(lmax, height[left]);
rmax = max(rmax, height[right]);
if (lmax < rmax)
{
res += lmax - height[left];
left++;
}
else
{
res += rmax - height[right];
right--;
}
}
return res;
}
};