[LeetCode] Trapping Rain Water 收集雨水
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:
Input: [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
这道收集雨水的题跟之前的那道 Largest Rectangle in Histogram 有些类似,但是又不太一样,先来看一种方法,这种方法是基于动态规划 Dynamic Programming 的,维护一个一维的 dp 数组,这个 DP 算法需要遍历两遍数组,第一遍在 dp[i] 中存入i位置左边的最大值,然后开始第二遍遍历数组,第二次遍历时找右边最大值,然后和左边最大值比较取其中的较小值,然后跟当前值 A[i] 相比,如果大于当前值,则将差值存入结果,参见代码如下:
C++ 解法一:
class Solution {
public:
int trap(vector<int>& height) {
int res = , mx = , n = height.size();
vector<int> dp(n, );
for (int i = ; i < n; ++i) {
dp[i] = mx;
mx = max(mx, height[i]);
}
mx = ;
for (int i = n - ; i >= ; --i) {
dp[i] = min(dp[i], mx);
mx = max(mx, height[i]);
if (dp[i] > height[i]) res += dp[i] - height[i];
}
return res;
}
};
Java 解法一:
public class Solution {
public int trap(int[] height) {
int res = 0, mx = 0, n = height.length;
int[] dp = new int[n];
for (int i = 0; i < n; ++i) {
dp[i] = mx;
mx = Math.max(mx, height[i]);
}
mx = 0;
for (int i = n - 1; i >= 0; --i) {
dp[i] = Math.min(dp[i], mx);
mx = Math.max(mx, height[i]);
if (dp[i] - height[i] > 0) res += dp[i] - height[i];
}
return res;
}
}
再看一种只需要遍历一次即可的解法,这个算法需要 left 和 right 两个指针分别指向数组的首尾位置,从两边向中间扫描,在当前两指针确定的范围内,先比较两头找出较小值,如果较小值是 left 指向的值,则从左向右扫描,如果较小值是 right 指向的值,则从右向左扫描,若遇到的值比当较小值小,则将差值存入结果,如遇到的值大,则重新确定新的窗口范围,以此类推直至 left 和 right 指针重合,参见代码如下:
C++ 解法二:
class Solution {
public:
int trap(vector<int>& height) {
int res = , l = , r = height.size() - ;
while (l < r) {
int mn = min(height[l], height[r]);
if (mn == height[l]) {
++l;
while (l < r && height[l] < mn) {
res += mn - height[l++];
}
} else {
--r;
while (l < r && height[r] < mn) {
res += mn - height[r--];
}
}
}
return res;
}
};
Java 解法二:
public class Solution {
public int trap(int[] height) {
int res = 0, l = 0, r = height.length - 1;
while (l < r) {
int mn = Math.min(height[l], height[r]);
if (height[l] == mn) {
++l;
while (l < r && height[l] < mn) {
res += mn - height[l++];
}
} else {
--r;
while (l < r && height[r] < mn) {
res += mn - height[r--];
}
}
}
return res;
}
}
我们可以对上面的解法进行进一步优化,使其更加简洁:
C++ 解法三:
class Solution {
public:
int trap(vector<int>& height) {
int l = , r = height.size() - , level = , res = ;
while (l < r) {
int lower = height[(height[l] < height[r]) ? l++ : r--];
level = max(level, lower);
res += level - lower;
}
return res;
}
};
Java 解法三:
public class Solution {
public int trap(int[] height) {
int l = 0, r = height.length - 1, level = 0, res = 0;
while (l < r) {
int lower = height[(height[l] < height[r]) ? l++ : r--];
level = Math.max(level, lower);
res += level - lower;
}
return res;
}
}
下面这种解法是用 stack 来做的,博主一开始都没有注意到这道题的 tag 还有 stack,所以以后在总结的时候还是要多多留意一下标签啊。其实用 stack 的方法博主感觉更容易理解,思路是,遍历高度,如果此时栈为空,或者当前高度小于等于栈顶高度,则把当前高度的坐标压入栈,注意这里不直接把高度压入栈,而是把坐标压入栈,这样方便在后来算水平距离。当遇到比栈顶高度大的时候,就说明有可能会有坑存在,可以装雨水。此时栈里至少有一个高度,如果只有一个的话,那么不能形成坑,直接跳过,如果多余一个的话,那么此时把栈顶元素取出来当作坑,新的栈顶元素就是左边界,当前高度是右边界,只要取二者较小的,减去坑的高度,长度就是右边界坐标减去左边界坐标再减1,二者相乘就是盛水量啦,参见代码如下:
C++ 解法四:
class Solution {
public:
int trap(vector<int>& height) {
stack<int> st;
int i = , res = , n = height.size();
while (i < n) {
if (st.empty() || height[i] <= height[st.top()]) {
st.push(i++);
} else {
int t = st.top(); st.pop();
if (st.empty()) continue;
res += (min(height[i], height[st.top()]) - height[t]) * (i - st.top() - );
}
}
return res;
}
};
Java 解法四:
class Solution {
public int trap(int[] height) {
Stack<Integer> s = new Stack<Integer>();
int i = 0, n = height.length, res = 0;
while (i < n) {
if (s.isEmpty() || height[i] <= height[s.peek()]) {
s.push(i++);
} else {
int t = s.pop();
if (s.isEmpty()) continue;
res += (Math.min(height[i], height[s.peek()]) - height[t]) * (i - s.peek() - 1);
}
}
return res;
}
}
Github 同步地址:
https://github.com/grandyang/leetcode/issues/42
类似题目:
参考资料:
https://leetcode.com/problems/trapping-rain-water/
https://leetcode.com/problems/trapping-rain-water/discuss/17364/7-lines-C-C%2B%2B
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Trapping Rain Water 收集雨水的更多相关文章
- [LeetCode] 42. Trapping Rain Water 收集雨水
Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...
- [LintCode] Trapping Rain Water 收集雨水
Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...
- [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 ...
- LeetCode: Trapping Rain Water 解题报告
https://oj.leetcode.com/problems/trapping-rain-water/ Trapping Rain WaterGiven n non-negative intege ...
- 【LeetCode】42. Trapping Rain Water 接雨水 (C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力求解 保存左右最大值 单调栈 日期 题目地址:ht ...
- 【LeetCode每天一题】Trapping Rain Water(获得雨水的容量)
Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...
- 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 ...
- [leetcode]Trapping Rain Water @ Python
原题地址:https://oj.leetcode.com/problems/trapping-rain-water/ 题意: Given n non-negative integers represe ...
- Leetcode Trapping Rain Water
Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...
随机推荐
- CloudNotes之桌面客户端篇:笔记撰写样式的支持
最近在CloudNotes桌面客户端中新增了笔记撰写样式的功能.当用户新建笔记的时候,可以在输入笔记标题的同时,选择笔记撰写样式,由安装包默认提供的样式主要有默认样式(Default).羊皮纸样式(L ...
- xcode7.1新建项目等问题
一.LaunchImage不显示 解决办法: 1.在Assets.xcassets新建LaunchImage并加入不同屏幕的launchImage 2.点击项目名,点击TARGETS,选择Genera ...
- Node学习笔记(四):gulp+express+io.socket部署angularJs2(填坑篇)
这篇就先暂停下上篇博客--你画我猜的进度,因为在做这个游戏的时候,想采用最新的ng2技术,奈何坑是一片又一片,这边就先介绍下环境部署和填坑史 既然要用ng2,首先要拿到资源,我这边用的是angular ...
- Redis命令拾遗三(列表List类型)
本文版权归博客园和作者吴双本人共同所有.转载和爬虫请注明原文地址 Redis五种数据类型之列表类型 Redis五种数据类型之列表类型.你可以存储一个有序的字符串列表一类数据.比如你想展示你所存储的所有 ...
- 小试ASP.NET MVC——一个邀请页面的实现
上篇博客我们大体介绍了ASP.NET MVC以及如何去新建项目,这篇博客我们讲点干货.小试ASP.NET MVC,我们来写一个简单的邀请WEB. 先来建立一个Models,叫GuestResponse ...
- C#开发微信门户及应用(12)-使用语音处理
我们知道,微信最开始就是做语音聊天而使得其更加流行的,因此语音的识别处理自然也就成为微信交流的一个重要途径,微信的开发接口,也提供了对语音的消息请求处理.本文主要介绍如何利用语音的识别,对C#开发的微 ...
- C#开发微信门户及应用(1)--开始使用微信接口
微信应用如火如荼,很多公司都希望搭上信息快车,这个是一个商机,也是一个技术的方向,因此,有空研究下.学习下微信的相关开发,也就成为日常计划的重要事情之一了.本系列文章希望从一个循序渐进的角度上,全面介 ...
- ASP.NET从MVC5升级到MVC6 RC2 总目录 - 发布在RC2Release之后
序言 随着MVC6RC2的推出,MVC6的脚步越来越近了.但是在我们的手里,有大批量的MVC5的项目.如何将MVC5升级到MVC6,将是一个很大的课题.微软官方暂时没有一个升级指导,或者一个迁移工具, ...
- .NET DateTime类型变量作为参数时设置默认值
一个小的 Tips. .NET 中函数参数的默认值需要是编译时常量.如果参数是引用类型,可以设置Null,如果是值类型,可以设置相应的编译时常量,如整型可以用整数,但对于DateTime(结构体,值类 ...
- spring mvc 和spring security配置 web.xml设置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmln ...