42. Trapping Rain Water
https://leetcode.com/problems/trapping-rain-water/#/solutions
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!
Fb: O(1)space
这种方法是基于动态规划的,基本思路就是维护一个长度为n的数组,进行两次扫描,一次从左往右,一次从右往左。第一次扫描的时候维护对于每一个bar左边最大的高度是多少,存入数组对应元素中,第二次扫描的时候维护右边最大的高度,并且比较将左边和右边小的最大高度(我们成为瓶颈)存入数组对应元素中。这样两遍扫描之后就可以得到每一个bar能承受的最大水量,从而累加得出结果。这个方法只需要两次扫描,所以时间复杂度是O(2*n)=O(n)。空间上需要一个长度为n的数组,复杂度是O(n)。代码如下:
常规做法:
public int trap(int[] height) { int[] A = height; if(A==null || A.length==0) return 0; int max = 0; int res = 0; int[] container = new int[A.length]; for(int i=0;i<A.length;i++) { max = Math.max(max,A[i]); container[i]=max; } max = 0; for(int i=A.length-1;i>=0;i--) { max = Math.max(max,A[i]); container[i] = Math.min(max,container[i]); res += container[i]-A[i]>0?container[i]-A[i]:0; } return res; }
Here is my idea: instead of calculating area by height*width, we can think it in a cumulative way. In other words, sum water amount of each bin(width=1).
Search from left to right and maintain a max height of left and right separately, which is like a one-side wall of partial container. Fix the higher one and flow water from the lower part. For example, if current height of left is lower, we fill water in the left bin. Until left meets right, we filled the whole container.
左右指针、最大值维护、正序、逆序
public int trap(int[] A){ int a=0; int b=A.length-1; int max=0; int leftmax=0; int rightmax=0; while(a<=b){ leftmax=Math.max(leftmax,A[a]); rightmax=Math.max(rightmax,A[b]); if(leftmax<rightmax){ max+=(leftmax-A[a]); // leftmax is smaller than rightmax, so the (leftmax-A[a]) water can be stored a++; } else{ max+=(rightmax-A[b]); b--; } } return max; }