这道题我本来的做法是
使用两个指针定住两头第一个非零元素,然后计算中间有多少个0,就表示多少个“坑”
然后依次-1,再重复上述操作
但是遇到height[i]
为上千的数字,就很蠢了。。。
并且超时
class Solution {
public:int trap(vector<int>& height) {int ans = 0;int n = height.size();int L = 0, R = n - 1;while (L < R) {while (L < n && height[L] == 0) ++L;while (R >= 0 && height[R] == 0) --R;if (L >= R) break;int cnt = 0;for (int i = L; i <= R; ++i) {if (height[i] == 0) {++cnt;} else {--height[i];}}ans += cnt;}return ans;}
};
于是,看了题解,决定使用单调栈的方法。
其实难点不在于方法是哪个,难点在于选择如何计算雨水的面积。
在这个方法里,相当于找到元素i
两边第一个比其高的圆柱,形成一个“坑”
这个“坑”接到的雨水的面积就等于高乘宽
高为两边高度中的较小值-
元素i
的高度(min(height[leftMax], height[rightMax]) - height[cur])
宽为两边高圆柱的下标相减再减1(rightMax - leftMax - 1)
使用单调栈主要就是找到元素i
的两边第一个比它高的圆柱
从左向右遍历,构建单调递增栈(即出栈元素成单调递增序列,即栈顶到栈底元素单调递增),假设元素i
已在栈顶,则即将进入栈的比它值大的元素为其右边第一个比它高的圆柱,而其栈内的下一个元素就是左边第一个比它高的圆柱,切记,单调栈内部记录了已经遍历了的元素。
class Solution {
public:int trap(vector<int>& height) {int ans = 0;stack<int> st;int n = height.size();for (int i = 0; i < n; ++i) {while (!st.empty() && height[i] > height[st.top()]) {int cur = st.top();st.pop();if (st.empty()) break;int leftMax = st.top();int rightMax = i;ans += (rightMax - leftMax - 1) * (min(height[leftMax], height[rightMax]) - height[cur]);}st.push(i); // 这里注意要入栈才算遍历过去}return ans;}
};
以这个输入样例为例,雨水面积依次计算顺序如图
输入:height = [4,2,0,3,2,5]
输出:9