Leetcode 042 - 接雨水
问题描述:给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例:输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
1 暴力法
暴力计算,空间占用最小,最费时
class Solution {
public:
int trap(vector<int>& height) {
int size = height.size();
int sum = 0;
for(int i = 1; i < size - 1; i++){
int leftMax = getMax(height, 0, i);
int rightMax = getMax(height, i+1, size);
int curmin = min(leftMax, rightMax);
if (curmin > height[i]) // 当两端最大值的较小一个大于本身,可以接到雨水
sum += (min(leftMax, rightMax) - height[i]);
}
return sum;
}
private:
int getMax(vector<int>& height, int left, int right){
int max = height[left];
for(int i = left + 1; i < right; i++){
if (height[i] > max){
max = height[i];
}
}
return max;
}
};
2 牺牲空间换时间
在1基础上,将每一位置左右两侧的最大值暂存起来,时间复杂度可由 O ( n 2 ) O(n^2) O(n2)减小为 O ( n ) O(n) O(n),空间复杂度由 O ( 1 ) O(1) O(1)增加为 O ( n ) O(n) O(n)
求最大值的方法参考动态规划思想,也即:
LeftMax[i] = max(LeftMax[i-1], height[i-1])
RightMax[i] = max(RightMax[i+1], height[i+1])
class Solution {
public:
int trap(vector<int>& height) {
int size = height.size();
vector<int> leftMax = getLeftMax(height, size);
vector<int> rightMax = getRightMax(height, size);
int sum = 0;
for(int i = 1; i < size - 1; i++){
int curmin = min(leftMax[i], rightMax[i]);
if (curmin > height[i]) // 当两端最大值的较小一个大于本身,可以接到雨水
sum += (curmin - height[i]);
}
return sum;
}
private:
vector<int> getLeftMax(vector<int>& height, int size){
vector<int> leftMax;
leftMax.push_back(0); // 左侧第一个元素左边最大值为0
for(int i = 1; i < size; i++){
leftMax.push_back(max(leftMax[i-1], height[i-1]));
}
return leftMax;
}
vector<int> getRightMax(vector<int>& height, int size){
vector<int> rightMax;
rightMax.push_back(0); // 右侧第一个元素右边最大值为0
for(int i = size - 2; i >= 0; i--){
rightMax.insert(rightMax.begin(), max(rightMax[0], height[i+1]));
}
return rightMax;
}
};
提交时间 | 提交结果 | 执行用时 | 内存消耗 | 语言 |
---|---|---|---|---|
暂存最大值法 | 通过 | 112 ms | 7.4 MB | Cpp |
暴力解法 | 通过 | 588 ms | 6.8 MB | Cpp |
还有个更精妙的优化方法,时间关系没有实现,想学习的朋友可查看 leetcode官方解答
3 借助栈存储
class Solution {
public:
int trap(vector<int>& height) {
int size = height.size();
stack<int> temp;
int sum = 0;
for(int i = 0; i < size; i++){
// 当前位置墙高大于栈顶位置墙高,出栈
while (!temp.empty() && height[i] >= height[temp.top()]){
int top = temp.top(); // 记录出栈位置
temp.pop();
if(temp.empty()){
break;
}
sum += ((i - temp.top() - 1) * (min(height[i], height[temp.top()]) - height[top]));
}
temp.push(i);
}
return sum;
}
};