LeetCode 42. 接雨水
算法1
(三次线性扫描)\(O(n)\)
每一列能储水的量,由该列左边最高的柱子,和该列右边最高的柱子决定。计算公式为\(V[i] = min(左边最高的柱子高度,右边最高的柱子高度)-height[i]\)
-
先线性扫描一遍,统计出每个柱子左边最高柱子的高度(这个最高的柱子有可能是自己)
-
再扫描一遍,统计出每个柱子右边最高柱子的高度
-
最后计算总的结果
时间复杂度
线性扫描三遍,所以是\(O(3n)\),也就是\(O(n)\)
空间复杂度
需要额外使用两个数组,\(O(n)\)
C++ 代码
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if (!n) return 0;
vector<int> left(n), right(n);
left[0] = height[0];
for (int i = 1; i < n; i ++)
left[i] = max(left[i-1], height[i]);
right[n-1] = height[n-1];
for (int i = n-2; i >= 0; i --)
right[i] = max(right[i+1], height[i]);
int res = 0;
for (int i = 0; i < n; i ++)
res += min(left[i], right[i]) - height[i];
return res;
}
};
算法2
(单调栈)\(O(n)\)
对于每一个柱子,我们将其视为能够储水的凹槽的右边的柱子,去搜索在它左边能够构成凹槽的两个要素:一个比自己矮的柱子\(a\),和一个比\(a\)要高、在\(a\)左边的的柱子\(b\)。第一个要素我们可以在遍历的时候设定条件,第二个要素我们发现有这样的逆序关系:\(height[a] < height[b]\)但是\(a>b\),因此我们可以使用一个严格单调递减的单调栈来储存这些柱子。设单调栈为\(st\)
- 线性扫描,当要加入的柱子比栈顶元素
st.top()高,则获取第一个要素,凹槽的底部,记作low_index然后出栈。 - 之后,假如栈不空的话,出栈之后的
st的栈顶元素st.top()就是我们要找的第二个要素,凹槽的左侧,记作left_high_index - 计算当前形成的凹槽容量,
V = (i - left_high_index - 1) * (min(height[left_high_index], height[i]) - height[low_index]);
时间复杂度
每个元素最多只会被入栈出栈一次,所以是\(O(n)\)
空间复杂度
额外使用了一个数组来维护单调栈,所以是\(O(n)\)
C++ 代码
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if (!n) return 0;
vector<int> st(n);
int res = 0;
for (int i = 0; i < n; i ++)
{
while(!st.empty() && height[i] >= height[st.back()])
{
int low_index = st.back();
st.pop_back();
if (st.empty()) break;
int left_high_index = st.back();
res += (i - left_high_index - 1) * (min(height[i], height[left_high_index]) - height[low_index]);
}
st.push_back(i);
}
return res;
}
};

浙公网安备 33010602011771号