给定 n 个非负整数表示每个宽度为 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 个单位的雨水(蓝色部分表示雨水)。

方法1:

维护单调递减栈,存放的是索引。 大于栈顶时开始计算雨水。
栈顶能盛的雨水:先出栈存为a
(min(右边大于它的height[i], 左边大于它的height[temp.top()]) - 它的高度height[a] )* (右边索引i - 左边索引temp.top() + 1)
比较难理解 看解析吧:说明

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> temp;
        int ans = 0;
        for (int i = 0; i < height.size(); i++) {
            while (!temp.empty() && height[i] >= height[temp.top()]) {
                //min(右边大于它的,左边大于它的)-它的高度    *   右边索引-左边索引+1
                int a = temp.top(); temp.pop();
                if (!temp.empty())//避免数据开头 0 1的情况
                    ans += (min(height[i], height[temp.top()]) - height[a]) * (i - temp.top() - 1);
            }
            temp.push(i);
        }
        return ans;
    }
};

方法2:

思路: 每一位置可以承接雨水的大小= min(它左边的最大值,它右边的最大值)-该位置的高度
所以找到左边的最大值和右边的最大值,left用打擂台更新,right也随循环更新

class Solution {
public:
    int max(vector<int>& height, int start, int end) {
        int ans = 0;
        for (int i = start; i <= end; i++)
            if (height[i] > ans) ans = height[i];
        return ans;
    }
    int trap(vector<int>& height) {
        if (height.size() == 0) return 0;
        int left = height[0], right = max(height, 0, height.size() - 1);
        int ans = 0;
        for (int i = 1; i < height.size(); i++) {
            if (height[i] > left) left = height[i];
            if (height[i - 1] == right) right = max(height, i, height.size() - 1);
            ans += min(left, right) - height[i];
        }
        return ans;
    }
};