42. 接雨水
给定 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
提示:
n == height.length
0 <= n <= 3 * 104
0 <= height[i] <= 105
这道题目可谓经典,我做了三次还是没法流畅地写出来,所以我决定把各种解法给它整理一遍,这样我肯定会啦!
方法一:水平方向 + 单调栈
当前元素比栈顶元素大的时候,就弹栈,用当前栈顶与之前栈顶元素的高度差 乘以 当前i位置与当前栈顶元素的距离减一更新ans
class Solution { public: int trap(vector<int>& height) { stack<int> st; int ans = 0; for(int i = 0; i < height.size(); i++){ while(!st.empty() && height[st.top()] < height[i]){ int id = st.top(); while(!st.empty() && height[st.top()] == height[id]) st.pop(); if(!st.empty()){ int k = st.top(); ans += (min(height[k], height[i]) - height[id]) * (i - k - 1); } } st.push(i); } return ans; } };
方法二:动态规划
当前位置 i 能接住的最大雨水高度取决于它左右两边最高的柱子的高度中较低的那一个
class Solution { public: int trap(vector<int>& height) { //动态规划 int n = height.size(); if(n == 0) return 0; vector<int> leftMax(n, 0); vector<int> rightMax(n, 0); leftMax[0] = height[0]; rightMax[n - 1] = height[n - 1]; for(int i = 1; i < n; i++){ leftMax[i] = max(leftMax[i - 1], height[i]); } for(int i = n - 2; i >= 0; i--){ rightMax[i] = max(rightMax[i + 1], height[i]); } int ans = 0; for(int i = 1; i < n - 1; i++){ ans += min(leftMax[i], rightMax[i]) - height[i]; //cout<<ans<<endl; } return ans; } };