Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.


The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image!

Example:

  1. Input: [0,1,0,2,1,0,1,3,2,1,2,1]
  2. Output: 6

这道收集雨水的题跟之前的那道 Largest Rectangle in Histogram 有些类似,但是又不太一样,先来看一种方法,这种方法是基于动态规划 Dynamic Programming 的,维护一个一维的 dp 数组,这个 DP 算法需要遍历两遍数组,第一遍在 dp[i] 中存入i位置左边的最大值,然后开始第二遍遍历数组,第二次遍历时找右边最大值,然后和左边最大值比较取其中的较小值,然后跟当前值 A[i] 相比,如果大于当前值,则将差值存入结果,参见代码如下:

C++ 解法一:

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

Java 解法一:

  1. public class Solution {
  2. public int trap(int[] height) {
  3. int res = 0, mx = 0, n = height.length;
  4. int[] dp = new int[n];
  5. for (int i = 0; i < n; ++i) {
  6. dp[i] = mx;
  7. mx = Math.max(mx, height[i]);
  8. }
  9. mx = 0;
  10. for (int i = n - 1; i >= 0; --i) {
  11. dp[i] = Math.min(dp[i], mx);
  12. mx = Math.max(mx, height[i]);
  13. if (dp[i] - height[i] > 0) res += dp[i] - height[i];
  14. }
  15. return res;
  16. }
  17. }

再看一种只需要遍历一次即可的解法,这个算法需要 left 和 right 两个指针分别指向数组的首尾位置,从两边向中间扫描,在当前两指针确定的范围内,先比较两头找出较小值,如果较小值是 left 指向的值,则从左向右扫描,如果较小值是 right 指向的值,则从右向左扫描,若遇到的值比当较小值小,则将差值存入结果,如遇到的值大,则重新确定新的窗口范围,以此类推直至 left 和 right 指针重合,参见代码如下:

C++ 解法二:

  1. class Solution {
  2. public:
  3. int trap(vector<int>& height) {
  4. int res = , l = , r = height.size() - ;
  5. while (l < r) {
  6. int mn = min(height[l], height[r]);
  7. if (mn == height[l]) {
  8. ++l;
  9. while (l < r && height[l] < mn) {
  10. res += mn - height[l++];
  11. }
  12. } else {
  13. --r;
  14. while (l < r && height[r] < mn) {
  15. res += mn - height[r--];
  16. }
  17. }
  18. }
  19. return res;
  20. }
  21. };

Java 解法二:

  1. public class Solution {
  2. public int trap(int[] height) {
  3. int res = 0, l = 0, r = height.length - 1;
  4. while (l < r) {
  5. int mn = Math.min(height[l], height[r]);
  6. if (height[l] == mn) {
  7. ++l;
  8. while (l < r && height[l] < mn) {
  9. res += mn - height[l++];
  10. }
  11. } else {
  12. --r;
  13. while (l < r && height[r] < mn) {
  14. res += mn - height[r--];
  15. }
  16. }
  17. }
  18. return res;
  19. }
  20. }

我们可以对上面的解法进行进一步优化,使其更加简洁:

C++ 解法三:

  1. class Solution {
  2. public:
  3. int trap(vector<int>& height) {
  4. int l = , r = height.size() - , level = , res = ;
  5. while (l < r) {
  6. int lower = height[(height[l] < height[r]) ? l++ : r--];
  7. level = max(level, lower);
  8. res += level - lower;
  9. }
  10. return res;
  11. }
  12. };

Java 解法三:

  1. public class Solution {
  2. public int trap(int[] height) {
  3. int l = 0, r = height.length - 1, level = 0, res = 0;
  4. while (l < r) {
  5. int lower = height[(height[l] < height[r]) ? l++ : r--];
  6. level = Math.max(level, lower);
  7. res += level - lower;
  8. }
  9. return res;
  10. }
  11. }

下面这种解法是用 stack 来做的,博主一开始都没有注意到这道题的 tag 还有 stack,所以以后在总结的时候还是要多多留意一下标签啊。其实用 stack 的方法博主感觉更容易理解,思路是,遍历高度,如果此时栈为空,或者当前高度小于等于栈顶高度,则把当前高度的坐标压入栈,注意这里不直接把高度压入栈,而是把坐标压入栈,这样方便在后来算水平距离。当遇到比栈顶高度大的时候,就说明有可能会有坑存在,可以装雨水。此时栈里至少有一个高度,如果只有一个的话,那么不能形成坑,直接跳过,如果多余一个的话,那么此时把栈顶元素取出来当作坑,新的栈顶元素就是左边界,当前高度是右边界,只要取二者较小的,减去坑的高度,长度就是右边界坐标减去左边界坐标再减1,二者相乘就是盛水量啦,参见代码如下:

C++ 解法四:

  1. class Solution {
  2. public:
  3. int trap(vector<int>& height) {
  4. stack<int> st;
  5. int i = , res = , n = height.size();
  6. while (i < n) {
  7. if (st.empty() || height[i] <= height[st.top()]) {
  8. st.push(i++);
  9. } else {
  10. int t = st.top(); st.pop();
  11. if (st.empty()) continue;
  12. res += (min(height[i], height[st.top()]) - height[t]) * (i - st.top() - );
  13. }
  14. }
  15. return res;
  16. }
  17. };

Java 解法四:

  1. class Solution {
  2. public int trap(int[] height) {
  3. Stack<Integer> s = new Stack<Integer>();
  4. int i = 0, n = height.length, res = 0;
  5. while (i < n) {
  6. if (s.isEmpty() || height[i] <= height[s.peek()]) {
  7. s.push(i++);
  8. } else {
  9. int t = s.pop();
  10. if (s.isEmpty()) continue;
  11. res += (Math.min(height[i], height[s.peek()]) - height[t]) * (i - s.peek() - 1);
  12. }
  13. }
  14. return res;
  15. }
  16. }

Github 同步地址:

https://github.com/grandyang/leetcode/issues/42

类似题目:

Trapping Rain Water II

Container With Most Water

Product of Array Except Self

Pour Water

参考资料:

https://leetcode.com/problems/trapping-rain-water/

https://leetcode.com/problems/trapping-rain-water/discuss/17364/7-lines-C-C%2B%2B

https://leetcode.com/problems/trapping-rain-water/discuss/17414/A-stack-based-solution-for-reference-inspired-by-Histogram

https://leetcode.com/problems/trapping-rain-water/discuss/17357/Sharing-my-simple-c%2B%2B-code%3A-O(n)-time-O(1)-space

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Trapping Rain Water 收集雨水的更多相关文章

  1. [LeetCode] 42. Trapping Rain Water 收集雨水

    Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...

  2. [LintCode] Trapping Rain Water 收集雨水

    Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...

  3. [LeetCode] Trapping Rain Water II 收集雨水之二

    Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...

  4. LeetCode: Trapping Rain Water 解题报告

    https://oj.leetcode.com/problems/trapping-rain-water/ Trapping Rain WaterGiven n non-negative intege ...

  5. 【LeetCode】42. Trapping Rain Water 接雨水 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力求解 保存左右最大值 单调栈 日期 题目地址:ht ...

  6. 【LeetCode每天一题】Trapping Rain Water(获得雨水的容量)

    Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...

  7. Leetcode: Trapping Rain Water II

    Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevati ...

  8. [leetcode]Trapping Rain Water @ Python

    原题地址:https://oj.leetcode.com/problems/trapping-rain-water/ 题意: Given n non-negative integers represe ...

  9. Leetcode Trapping Rain Water

    Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...

随机推荐

  1. 用 jQuery.ajaxSetup 实现对请求和响应数据的过滤

    不知道同学们在做项目的过程中有没有相同的经历呢?在使用 ajax 的时候,需要对请求参数和响应数据进行过滤处理,比如你们觉得就让请求参数和响应信息就这么赤裸裸的在互联网里来回的穿梭,比如这样: 要知道 ...

  2. 你真的会玩SQL吗?透视转换的艺术

    你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...

  3. Android keycode列表

    整理备忘! 基本按键 KEYCODE_0 按键'0' 7 KEYCODE_1 按键'1' 8 KEYCODE_2 按键'2' 9 KEYCODE_3 按键'3' 10 KEYCODE_4 按键'4' ...

  4. 基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(二)

    我们上一篇<基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)>主要讲解了如何搭建一个实时数据通讯服务器,客户端与服务端是如何通讯的,相信通过上一篇的讲解,再配 ...

  5. Ionic2系列-将beta升级到RC1

    国庆节前Ionic2发布了RC0版本,已经接近正式版了,前不久Angular2和TypeScript2也已经发布了正式版.详情请参考官方博客: http://blog.ionic.io/announc ...

  6. 创建虚拟目录失败,必须为服务器名称指定“localhost”?看进来!!

    没废话,直接讲! 关于微信开发过程,远程调试后,再次打开vs出现项目加载失败的解决办法! 上图: 这图应该不陌生,你肯定打开iis把绑定的域名给干掉了.这个提示很坑人,简直就是坑爹!!!fck!! 来 ...

  7. Windows下删除.svn文件夹的最简易方法

    建立一个文本文件,取名为kill-svn-folders.reg(扩展名由txt改为reg),内容如下: Windows Registry Editor Version 5.00 [HKEY_LOCA ...

  8. 使用page object模式抓取几个主要城市的pm2.5并从小到大排序后写入txt文档

    #coding=utf-8from time import sleepimport unittestfrom selenium import webdriverfrom selenium.webdri ...

  9. Python 基础之三条件判断与循环

    If……else 基本结构: If condition: do something else: do something 或者 If condition: do something elif cond ...

  10. Json CPP 中文支持与入门示例

    在每一个Json Cpp自带*.cpp文件头加上: #include "stdafx.h" 将Json Cpp对自带的头文件的引用修改为单引号方式,例如json_reader.cp ...