给定 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 * 104
0 <= height[i] <= 105
本题根据B站up主:灵茶山艾府 思路解题
我们把每一个格都看作一个单独的桶
有两种方法:我们分别从前和后两个方向遍历数组,分别得到每一个位置的前后缀,我们知道一个木桶能够装水的容量取决于短的那块板,因此得到一个前缀数组和一个后缀数组后,我们就能通过比较得到每一个位置的装水容量大小,关于如何得到这个前后缀数组,我们遍历数组时通过更新最大长度可以得到前后缀,因为这个木桶能装水的多少不会比这个最大值还要大,一个桶溢出,水会流向更别的桶,只要这个桶的板子够长,因此我们取最大值。最后,得到前后缀后,用前后缀的较小值减去木桶高度height[i],就得到了装水量。
class Solution {
public:
int trap(vector<int>& height) {
int n=height.size();
int leftMax[n];
int rightMax[n];
leftMax[0]=height[0];
for(int i=1;i<n;i++)
{
leftMax[i]=max(leftMax[i-1],height[i]);
}
rightMax[n-1]=height[n-1];
for(int j=n-2;j>=0;j--)
{
rightMax[j]=max(rightMax[j+1],height[j]);
}
int res=0;
for(int i=0;i<n;i++)
{
res+=min(leftMax[i],rightMax[i])-height[i];
}
return res;
}
};
另一种解法我们可以采用双指针,可以不使用这两个数组,减少空间的消耗。同样是从前后遍历数组,我们用两个值leftMax和rightMax表示左边和右边的最大值,在遍历时实时更新,leftmax=max(leftmax,height[i]),rightMax=max(rightMax,height[j]),用这两个最大值来卡一个桶的前后缀,如果leftMax>rightMax,说明这个桶的能装水的量一定不会大于rightMax-height[i],同时更新右值往前挪一步,反之同理,最终我们将每一个桶的容量加起来,就是总的雨水量。
代码:
class Solution {
public:
int trap(vector<int>& height) {
int n=height.size();
int res=0;
int leftMax=height[0];
int rightMax=height[n-1];
int i=1;
int j=n-2;
while(i<=j)
{
leftMax=max(leftMax,height[i]);
rightMax=max(rightMax,height[j]);
if(leftMax>rightMax)
{
res+=rightMax-height[j];
j--;
}
else
{
res+=leftMax-height[i];
i++;
}
}
return res;
}
};