题目
给定 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
解法
解法一(暴力解法)
- 超出时间限制
算法
逐个计算每一列能存下的水量。
遍历整个数组。针对数组中的每个元素arr[i],都分别向左、向右遍历一遍数组,找到arr[i]左侧和右侧的最大值,计为leftMax和rightMax,如果leftMax <= arr[i]或者rightMax <= arr[i],说明当前这一列存不出水。否则当前列能存储的水量为min(leftMax, rightMax) - arr[i],则
res[i] = max{0, min{max(arr[0...i-1]), max(arr[i+1...n])} - arr[i] }
该式可化解为
res[i]=min{max{arr[0...i]},max{arr[i...n−1]}}−arr[i]
代码
class Solution {
public:
int trap(vector<int>& height) {
int sum = 0;
int n = height.size();
for (int i=0; i<n; i++) {
int leftMax = 0;
for (int j=0; j<=i; j++) {
if (height[j] > leftMax) {
leftMax = height[j];
}
}
int rightMax = 0;
for (int j=i; j<n; j++) {
if (height[j] > rightMax) {
rightMax = height[j];
}
}
sum += min(leftMax, rightMax) - height[i];
}
return sum;
}};
解法二(指针)
算法
由于暴力解法超出时间限制,我们可以将其进行改进,预处理数组得到leftMax[]和rightMax[]两个数组,leftMax[i]代表数组0到i位置的最大值,leftMax[i] = max(leftMax[i-1], arr[i]);rightMax[i]代表数组i位置到n-1位置的最大值,rightMax[i] = max(rightMax[i+1], arr[i]),遍历时可以直接进行引用。
代码
int trap(vector<int>& height) {
int n = height.size();
vector<int> leftMax(n, 0);
leftMax[0] = height[0];
for (int i=1; i<n; i++) {
leftMax[i] = max(leftMax[i-1], height[i]);
}
vector<int> rightMax(n, 0);
rightMax[n-1] = height[n-1];
for (int i=n-2; i>=0; i--) {
rightMax[i] = max(rightMax[i+1], height[i]);
}
int res = 0;
for (int i=0; i<n; i++) {
res += min(leftMax[i], rightMax[i]) - height[i];
}
return res;
}
解法三
算法:
设置两个指针,left
指向数组的0
位置,right
指针指向数组的n-1
位置。再使用两个变量leftMax
和rightMax
,leftMax
的含义是数组0...left
位置的最大值,rightMax
的含义是数组right...n-1
位置的最大值。
leftMax < rightMax
,此时可以使用leftMax
来结算height[left]
位置的储水量,res[left] = leftMax - height[left]。leftMax > rightMax
,此时可以使用rightMax
来结算right
位置的储水量,res[right] = rightMax - height[right]。leftMax == rightMax
,此时既可以结算左侧,也可以结算右侧,或者左右两侧可以同时结算储水量,res[left] = leftMax - height[left]
,res[right] = rightMax - height[right]。
代码
int trap(vector<int>& height) {
int n = height.size();
int leftMax = 0, rightMax = 0, left = 0, right = n-1, res = 0;
while (left <= right) {
leftMax = max(leftMax, height[left]);
rightMax = max(rightMax, height[right]);
if (leftMax < rightMax) {
// 左侧结算
res += leftMax - height[left++];
} else if (leftMax > rightMax) {
// 右侧结算
res += rightMax - height[right--];
} else {
// 双侧结算
res += leftMax - height[left++];
if (left <= right) {
res += rightMax - height[right--];
}
}
}
return res;
}
————————————-——————————————————————————————
内容参考:
https://blog.csdn.net/Jarvenman/article/details/135573958