摘要:
很容易就联想到使用栈来解决。
题目
给定 $n$ 个非负整数表示每个宽度为 $1$ 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。
示例:
输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6 
按列计算(动态规划计算最值)
遍历每列,判断要不要计算列上的积水。
如何判断?计算出该列左侧最高列高度,计算右侧最高列高度。
若该列比二者都小,则该列需要计算;否则不需计算。
如何分别计算某列两侧最值?
可维护两个数组分别存储每列左右两侧最值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   | class Solution {     
 
 
 
      public int trap(int[] height) {         int res = 0;         int len = height.length;         int[] leftSideMax = new int[len];         int[] rightSideMax = new int[len];                  for (int i = 1; i < len - 1; i++) {             leftSideMax[i] = Math.max(leftSideMax[i - 1], height[i - 1]);         }         for (int i = len - 2; i > 0; i--) {             rightSideMax[i] = Math.max(rightSideMax[i + 1], height[i + 1]);         }         for (int j = 1; j < len - 1; j++) {             int minimum = Math.min(leftSideMax[j], rightSideMax[j]);             if (height[j] < minimum) {                 res += (minimum - height[j]);             }         }         return res;     } }
  | 
 
单调栈
核心思想是先降后增必有积水。
这个就有点像有效括号,一对儿。
维护一个单调递减的栈,栈中存入柱子下标。(为什么存入下标而不直接存入高度?因为我们可能会计算两个相隔若干柱子之间的距离。)
入栈:栈为空时;当前柱子低于栈顶柱子。
出栈:当前柱子高于栈顶柱子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
   | 
 
 
  static const auto shutdown = []() {     cin.tie(nullptr)->sync_with_stdio(false);     return nullptr; }();
  class Solution { public:     static constexpr int N = 30010;     pair<int, int> stk[N];       int tt = 0;     int len;     int res = 0;
      int trap(vector<int>& height) {         this->len = height.size();
          for (int i = 0; i < len; i++) {             if (!tt || height[i] <= stk[tt].second) {                 stk[++tt] = {i, height[i]};                 continue;             }                                       for (; tt && height[i] > stk[tt].second;) {                    int stk_top_height = stk[tt].second;                 for (; tt; --tt) {                     if (stk[tt].second > stk_top_height) {                           int l = stk[tt].first, r = i;                         int lheight = stk[tt].second, rheight = height[i];                         res += (r - l - 1) * (min(lheight, rheight) - stk_top_height);                         break;                     }                 }                              }                          stk[++tt] = {i, height[i]};          }         return res;     } };
 
  | 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | class Solution {     
 
 
      public int trap(int[] height) {         int res = 0;         Stack<Integer> stack = new Stack<>();         int len = height.length;         for (int i = 0; i < len; i++) {             while (!stack.isEmpty() && height[i] > height[stack.peek()]) {                  int heightInfoBeforePop = stack.peek();                 stack.pop();                  if (stack.isEmpty()) break;                  else {                     int stackTop = stack.peek();                     res += ((i - stackTop - 1) * (Math.min(height[i], height[stackTop]) - height[heightInfoBeforePop]));                 }             }             stack.push(i);          }         return res;     } }
  |