首页 > 代码库 > LeetCode[Array]: Trapping Rain Water
LeetCode[Array]: 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!
这个题目我首先参考了这个Discuss的解法:https://oj.leetcode.com/discuss/18022/sharing-my-java-code-o-n-time-o-1-space
这个解法的思路如下:设置两个迭代器,一个从最左边开始,另外一个从最右边开始,首先去掉两边不可能蓄水的堤坝(以题目中的例子为例,最右侧的那个堤坝是不可能蓄水的);然后只要两个迭代器未相遇便进行如下循环:首先判断两侧堤坝的高度,从较低侧的堤坝往中间遍历,当发现堤坝高度小于或者等于这个较低高度时则将这个高度差加到蓄水和,否则进行下一次循环。至于为什么从较低侧堤坝遍历,我想这个比较容易想明白,因为较高侧并不能保证能够蓄水。
我在实现的时候,觉得没有必要进行第一步,即首先去掉两边不可能蓄水的堤坝,因为后面的循环依然可以去掉这些不能蓄水的堤坝。
我的C++代码实现如下:
int trap(int A[], int n) {
int water = 0;
for (int left = 0, right = n - 1; left < right; )
{
int leftHeight = A[left ];
int rightHeight = A[right];
if (leftHeight < rightHeight)
while (left < right && A[++left ] <= leftHeight ) water += (leftHeight - A[left ]);
else
while (left < right && A[--right] <= rightHeight) water += (rightHeight - A[right]);
}
return water;
}
我们从算法的过程中知道:虽然用了二层循环,但是实际上这是个One Pass算法;另外,我们知道要尽量用一层循环代替二层循环(http://blog.csdn.net/chfe007/article/details/25544421);由于这是个One Pass算法,因此改为一层循环完全是可行的,只需要增加左右两个基准高度即可,我的C++代码实现如下:
int trap(int A[], int n) {
int water = 0;
int leftStdHeight = 0, rightStdHeight = 0;
for (int left = 0, right = n - 1; left < right; ) {
if (A[left] <= A[right]) { A[left ] < leftStdHeight ? (water += leftStdHeight - A[left ]) : (leftStdHeight = A[left ]); ++left ; }
else { A[right] < rightStdHeight ? (water += rightStdHeight - A[right]) : (rightStdHeight = A[right]); --right; }
}
return water;
}
以上两种算法的时间复杂度都是O(N),空间复杂度都是O(1),时间性能表现,前者为11ms,后者为13ms,如下图所示:
另外,这个Discuss:https://oj.leetcode.com/discuss/3546/any-one-pass-solutions提出了一种用总面积减去堤坝本身占据的面积来完成的计算的算法,也可以借鉴一下。
LeetCode[Array]: Trapping Rain Water