42. 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.
For example,
Given [0,1,0,2,1,0,1,3,2,1,2,1]
, return 6
.
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!
链接: http://leetcode.com/problems/trapping-rain-water/
题解:
经典题目接雨水。对每个index单独进行考虑,则这个index左侧最高bar与右侧最高bar能组成一个容器,在这个容器里,左侧bar和右侧bar中较低的一个与当前index的差值就为当前index所能储存的雨水量。
Time Complexity - O(n), Space Complexity - O(n)。 可以只使用一个数组,但不如下面代码看起来思路清晰。另外有stack和双指针法,还有待了解。
public class Solution { public int trap(int[] height) { //dp if(height == null || height.length == 0) return 0; int[] forward = new int[height.length]; int[] backward = new int[height.length]; int[] res = new int[height.length]; int leftBar = height[0]; for(int i = 1; i < height.length - 1; i++) { forward[i] = leftBar; leftBar = Math.max(height[i], leftBar); } int rightBar = height[height.length - 1]; for(int i = height.length - 2; i >= 0; i--) { backward[i] = rightBar; rightBar = Math.max(height[i], rightBar); } int max = 0; for(int i = 1; i < height.length - 1; i++) { int curVolume = Math.min(forward[i], backward[i]) - height[i]; if(curVolume > 0) max += curVolume; } return max; } }
二刷:
这道题现在很熟悉了。就是记忆一下左边最大的leftBar,遍历一遍数组。再记忆一下右边最大的rightBar,遍历一遍数组。最后从 i = 1到i = height.length - 2,计算volumn = Math.min(leftBar, rightBar) - height[i],假如这个volumn大于等于0,则这个点的雨水可以被接,我们把这个volumn加入到最终结果中。
仔细查看了Discuss发现还有Space Complexity O(1)的解法。研究一下, 代码主要来自discuss里面的mcrystal,分为下面几个步骤
- 像Container with most water一样,设立一个lo = 0, hi = height.length - 1,使用双指针来夹逼遍历。
- 设立一个res = 0, maxLeftBar = 0, maxRightBar = 0
- 在 lo <= hi的条件下进行遍历
- 假如height[lo] <= height[hi],或者height[lo] < height[hi]也可以, 这时候说明当前左边的height <= 右边的height。那么我们只需要考虑左边界和当前左边的height的差值,这个差值就是我们能容纳多少水
- 在上述情况下,假如height[lo] >= maxLeftBar, 当前index的值 > maxLeftBar,那么我们不能接到水,我们要把maxLeftBar更新为height[lo]
- 否则res += maxLeftBar - height[lo],我们把这个差值加入到结果中
- lo++
- 否则,左边的当前height > 右边的当前height,容易能盛多少水取决于右边的height以及maxRightBar的差值
- 当height[hi] >= maxRightBar,我们更新maxRightBar = height[hi]
- 否则,我们把结果 maxRightBar - height[hi]加入到res中
- hi--
- 假如height[lo] <= height[hi],或者height[lo] < height[hi]也可以, 这时候说明当前左边的height <= 右边的height。那么我们只需要考虑左边界和当前左边的height的差值,这个差值就是我们能容纳多少水
- 最后返回结果res就可以了, 很巧妙。
Java:
Time Complexity - O(n), Space Complexity - O(n)
public class Solution { public int trap(int[] height) { if (height == null || height.length == 0) { return 0; } int n = height.length; int[] leftBars = new int[n]; int maxLeftBar = height[0]; for (int i = 1; i < height.length; i++) { leftBars[i] = maxLeftBar; maxLeftBar = Math.max(maxLeftBar, height[i]); } int[] rightBars = new int[n]; int maxRightBar = height[height.length - 1]; for (int i = height.length - 2; i >= 0; i--) { rightBars[i] = maxRightBar; maxRightBar = Math.max(maxRightBar, height[i]); } int res = 0; for (int i = 1; i < height.length - 1; i++) { int volumn = Math.min(leftBars[i], rightBars[i]) - height[i]; if (volumn > 0) { res += volumn; } } return res; } }
Time Complexity - O(n), Space Complexity - O(1)
public class Solution { public int trap(int[] height) { if (height == null || height.length == 0) { return 0; } int lo = 0, hi = height.length - 1; int maxLeftBar = 0, maxRightBar = 0; int res = 0; while (lo <= hi) { if (height[lo] <= height[hi]) { if (height[lo] >= maxLeftBar) { maxLeftBar = height[lo]; } else { res += maxLeftBar - height[lo]; } lo++; } else { if (height[hi] >= maxRightBar) { maxRightBar = height[hi]; } else { res += maxRightBar - height[hi]; } hi--; } } return res; } }
三刷:
Java:
1D dp: - Time Complexity - O(n), Space Complexity - O(n)
public class Solution { public int trap(int[] height) { if (height == null || height.length == 0) return 0; int len = height.length; int[] leftVolumns = new int[len]; int localMaxVol = height[0]; for (int i = 1; i < len - 1; i++) { leftVolumns[i] = localMaxVol; localMaxVol = Math.max(localMaxVol, height[i]); } localMaxVol = height[len - 1]; int res = 0; for (int i = len - 1; i > 0; i--) { int curVolumn = Math.min(leftVolumns[i], localMaxVol) - height[i]; if (curVolumn > 0) res += curVolumn; localMaxVol = Math.max(localMaxVol, height[i]); } return res; } }
2-pointers: - Time Complexity - O(n), Space Complexity - O(1)
public class Solution { public int trap(int[] height) { if (height == null || height.length == 0) return 0; int len = height.length; int lo = 0, hi = len - 1, maxLeftBar = 0, maxRightBar = 0; int res = 0; while (lo <= hi) { if (height[lo] <= height[hi]) { if (height[lo] < maxLeftBar) { res += maxLeftBar - height[lo]; } else { maxLeftBar = height[lo]; } lo++; } else { if (height[hi] < maxRightBar) { res += maxRightBar - height[hi]; } else { maxRightBar = height[hi]; } hi--; } } return res; } }
Reference:
http://www.cnblogs.com/springfor/p/3877101.html
https://leetcode.com/discuss/16171/sharing-my-simple-c-code-o-n-time-o-1-space
https://leetcode.com/discuss/10046/share-my-short-solution
https://leetcode.com/discuss/45812/7-lines-c-c
https://leetcode.com/discuss/45791/8-lines-c-c-java-python-solution
https://leetcode.com/discuss/27973/concise-o-1-space-java-solution