困难

题目描述

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。42. 接雨水 - 图1
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

来源,leetcode 每日一题 42. 接雨水

例如:

  1. 输入: [0,1,0,2,1,0,1,3,2,1,2,1]
  2. 输出: 6

解题思路

  1. 在暴力方法中,我们仅仅为了找到最大值每次都要向左和向右扫描一次。但是我们可以提前存储这个值。因此,可以通过动态编程解决。

这个概念可以见下图解释:
42. 接雨水 - 图2
对于位置i而言,就是找到i左边的最大值,和i右边的最大值,然后计算取小的一个,作为可盛水量的短边,然后将该短边减去当前点的高度,即为当前点可以存储的水量。
如何快速得到当前点左右两边的最大值呢?->动态规划。
对于位置i而言,它的左边最大边,有两种情况,如果当前位置的height大于前一个位置的maxheight,则最大边为其自身,否则和前一个位置的max_height相同。即如下公式表示:
![](https://cdn.nlark.com/yuque/__latex/1a8b56a9127b5919660ee9d6a3c9e3e2.svg#card=math&code=maxHeight_i%20%3D%20max%28height_i%2C%20maxHeight
%7Bi-1%7D%29&height=20&width=327).
右边最大边类似。

代码

  1. class Solution {
  2. public:
  3. int trap(vector<int>& height) {
  4. if (height.size() == 0)
  5. return 0;
  6. int ans = 0;
  7. int size = height.size();
  8. vector<int> left_max(size), right_max(size);
  9. left_max[0] = height[0];
  10. for (int i = 1; i < size; i++) {
  11. left_max[i] = max(height[i], left_max[i - 1]);
  12. }
  13. right_max[size - 1] = height[size - 1];
  14. for (int i = size - 2; i >= 0; i--) {
  15. right_max[i] = max(height[i], right_max[i + 1]);
  16. }
  17. for (int i = 1; i < size - 1; i++) {
  18. ans += min(left_max[i], right_max[i]) - height[i];
  19. }
  20. return ans;
  21. }
  22. };