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!
Analysis: For each element in the given array, the water it can contain is determined by its leftMaxBarValue and rightMaxBarValue.
if min(leftMaxBarValue, rightMaxBarValue)>currentBarValue, waterContained+=min(leftMaxBarValue, rightMaxBarValue)-currentBarValue
In order to get the left and right bounds for each element, we can scan the array two times:
1. FInd the index and value of the highest bar in the array.
2. Scan the array, the element on the left of the maxBarIndex should have maxBarValue as their rightMaxBarValue. Their leftMaxBarValue can be updated and determined on the way. Same logic works for the right part of the array, except that we should scan from the end to the maxBarIndex.
public class Solution {
public int trap(int[] A) {
int maxBarValue=0, maxBarIndex=-1;
for(int i=0; i<A.length; i++) {
if(A[i] >= maxBarValue) { // must be >= here
maxBarValue = A[i];
maxBarIndex = i;
}
}
if(maxBarValue==0 || maxBarIndex==-1) return 0;
int[] leftBound = new int[A.length];
int[] rightBound = new int[A.length];
int leftMax=0, rightMax=0;
for(int j=0; j<maxBarIndex; j++) { // 0 -> maxBarIndex
leftBound[j] = leftMax;
rightBound[j] = maxBarValue;
if(A[j]>leftMax) leftMax=A[j];
}
leftBound[maxBarIndex] = -1;
rightBound[maxBarIndex] = -1;
for(int k=A.length-1; k>=maxBarIndex+1; k--) { // A.length-1 -> maxBarIndex
leftBound[k] = maxBarValue;
rightBound[k] = rightMax;
if(A[k]>rightMax) rightMax=A[k];
}
int water = 0;
for(int m=0; m<A.length; m++) {
int lowBarValue = Math.min(leftBound[m], rightBound[m]);
if(lowBarValue>A[m]) water+=lowBarValue-A[m];
}
return water;
}
}