Trapping Rain Water

来源:互联网 发布:nginx重启命令 编辑:程序博客网 时间:2024/05/21 19:24

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!

Have you been asked this question in an interview? 
方法一: dp
两个for循环求出每个点左右两边的最高bar, 再用一个for 循环求出对于每个点可以的存水量。
该方法还可以优化 将求右边bar 和求最后结果合到一起 
注意:要考虑到 当前的a[i] 比左右两边的bar 高时,不进行操作

public class Solution {    public int trap(int[] A) {        if (A == null || A.length == 0) {            return 0;        }        int[] leftBar = new int[A.length];        leftBar[0] = 0;        for (int i = 1; i < A.length; i++) {            leftBar[i] = Math.max(leftBar[i - 1], A[i - 1]);        }        int[] rightBar = new int[A.length];        rightBar[A.length - 1] = 0;        for (int i = A.length - 2; i > 0; i--) {            rightBar[i] = Math.max(rightBar[i + 1], A[i + 1]);        }        int res = 0;        for (int i = 1; i < A.length - 1; i++) {            if (Math.min(leftBar[i], rightBar[i]) > A[i]) {                res += Math.min(leftBar[i], rightBar[i]) - A[i];            }        }        return res;    }}

将第二个和第三个 for 循环合并后:
public class Solution {    public int trap(int[] A) {        if (A == null || A.length == 0) {            return 0;        }        int[] leftBar = new int[A.length];        leftBar[0] = 0;        for (int i = 1; i < A.length; i++) {            leftBar[i] = Math.max(leftBar[i - 1], A[i - 1]);        }        int right = A[A.length - 1] ;        int res = 0;        for (int i = A.length - 2; i > 0; i--) {            if (Math.min(leftBar[i], right) > A[i]) {                res += Math.min(leftBar[i], right) - A[i];            }            right = Math.max(right, A[i]);        }        return res;    }}

九章的解法与以上方法有点不同,但是也很好理解:
public class Solution {    public int trap(int[] A) {        int sum = 0;        int max = -1;        int maxIndex = -1;        int prev;        // find the highest bar        for (int i = 0; i < A.length; i++) {            if (max < A[i]) {                max = A[i];                maxIndex = i;            }        }        // process all bars left to the highest bar        prev = 0;        for (int i = 0; i < maxIndex; i++) {            if (A[i] > prev) {                sum += (A[i] - prev) * (maxIndex - i);                prev = A[i];            }            sum -= A[i];        }        // process all bars right to the highest bar        prev = 0;        for (int i = A.length - 1; i > maxIndex; i--) {            if (A[i] > prev) {                sum += (A[i] - prev) * (i - maxIndex);                prev = A[i];            }            sum -= A[i];        }        return sum;    }}


还有一种比较聪明的方法是用stack, 时间复杂度都是 o(n), 但是 只用一次for 循环即可。这种方法 和 Largest Rectangle in Histogram 有点像

public class Solution {    public int trap(int[] A) {    Stack<Integer> pre = new Stack<Integer>();    int result = 0;    for(int i = 0; i < A.length; i++) {        if(pre.isEmpty() || A[pre.peek()] > A[i]) {            pre.push(i);            continue;        }        int mid = pre.pop();        if(pre.isEmpty()) pre.push(i);        else {            int left = pre.peek();            result += (Math.min(A[left], A[i])-A[mid]) * (i-left-1);            i--;        }    }    return result;    }}


0 0