给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
暴力方法比较容易思考,即按列计算当前列能装多少雨水。找到当前列的左端最大高度curMaxLeft
和右端最大高度curMaxRight
,比较出两端最大高度的最小值,再与当前列的高度进行比较,如果最小值大于当前高度,显然差值就是装雨水的量,否则,不能装雨水。
class Solution {
public:
int trap(vector<int>& height) {
if(height.size() < 3)
return 0;
int len = height.size();
int start = 0;
while(start < len && height[start] == 0)
start++;
int curMaxLeft = height[start];
int result = 0;
for(int i = start + 1; i < len - 1; i++){
int curMaxRight = getMax(height, i + 1, len - 1);
int curHeight = min(curMaxLeft, curMaxRight);
if(curHeight - height[i] > 0)
result += curHeight - height[i];
curMaxLeft = max(curMaxLeft, height[i]);
}
return result;
}
private:
int getMax(vector<int>& height, int start, int end){
int result = 0;
for(int i = start; i <= end; i++){
result = max(result, height[i]);
}
return result;
}
};
暴力法我们发现要不断获取当前列的左右端最大高度。我们可以用备忘录的方式,记录当前列的左右端最大高度,避免重复的运算。
curMaxLeft[i] = max(curMaxLeft[i - 1], height[i - 1]);
curMaxRight[i] = max(curMaxRight[i + 1], height[i + 1]);
class Solution {
public:
int trap(vector<int>& height) {
if(height.size() < 3)
return 0;
int result = 0;
int len = height.size();
vector<int> curMaxLeft(len);
vector<int> curMaxRight(len);
for(int i = 1; i < len - 1; i++)
curMaxLeft[i] = max(curMaxLeft[i - 1], height[i - 1]);
for(int i = len - 2; i >= 0; i--)
curMaxRight[i] = max(curMaxRight[i + 1], height[i + 1]);
for(int i = 1; i < len - 1; i++){
int cur = min(curMaxLeft[i], curMaxRight[i]);
if(cur - height[i] > 0)
result += cur - height[i];
}
return result;
}
};
现在考虑降低空间复杂度。观察前两种暴力解法,我们发现左端最大值我们是可以利用指针实时更新的,而右端则不行,因为左端最大值是从左到右遍历的,右端最大值是从右向左遍历的,一次循环的方向是从左向右,显然暴力法一次循环不能完成任务。
此时我们考虑双指针,实际上就是对备忘录的优化。备忘录中我们是先记录结果再计算,双指针我们是实时更新。
class Solution {
public:
int trap(vector<int>& height) {
if(height.size() < 3)
return 0;
int result = 0;
int len = height.size();
int left = 0, right = len - 1;
int curMaxLeft = height[0], curMaxRight = height[len - 1];
while(left <= right){
curMaxLeft = max(curMaxLeft, height[left]);
curMaxRight = max(curMaxRight, height[right]);
if(curMaxLeft > curMaxRight){
result += curMaxRight - height[right];
right--;
}
else{
result += curMaxLeft - height[left];
left++;
}
}
return result;
}
};
- 高赞1
- 高赞2
- 高赞3
- 官方题解
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。
本人blog:http://breadhunter.gitee.io