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.
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!
Example:
Input: [0,1,0,2,1,0,1,3,2,1,2,1] Output: 6
Solution:
An element of array can store water if there’re higher bar on left and right. Use two variables to store the left_max and right_max. The reason doing this is because the water trapped at any element= min(left_max, right_max)- height[i]. So we can calculate the water trapped on smaller element out of height[left] and height[right] first, then move the pointers with condition left <= right.
classSolution: deftrap(self, height: List[int]) -> int: # keep left_max, right_max to know if there's a higher bar # only move left pointer when height[left] is smaller than height[right] # only move right pointer when height[right] is smaller than height[left] res, left, right = 0, 0, len(height)-1 left_max, right_max = 0, 0 while left<= right: if height[left]< height[right]: if height[left]> left_max: left_max= height[left] else: res += left_max-height[left] left += 1 else: if height[right]> right_max: right_max= height[right] else: res+= right_max-height[right] right -= 1 return res
classSolution { public: inttrap(vector<int>& height){ // if an element of the array can store water, if has a bar on it's left and right int res= 0; int left= 0, right= height.size()-1; int left_max= 0, right_max= 0; while(left<= right){ if(height[left]< height[right]){ // this means height[right] is definitely a bar, so just consider left side below if(height[left]> left_max) left_max= height[left]; else res += left_max-height[left]; left++; } else{ if(height[right]> right_max) right_max= height[right]; else res+= right_max-height[right]; right--; } } return res; } };
Solution DP
The idea is to know what the max height is, to the left and right of every index. Think about it- at any given index, there can only be trapped rain water above it if the min(max_height_to_the_left, max_height_to_the_right) is bigger than the height at this particular index.
classSolution: deftrap(self, height: List[int]) -> int: tmp_left, tmp_right, n = 0, 0, len(height) max_left, max_right = [0]*n, [0]*n for i in range(n): max_left[i] = tmp_left # index i's left boundary is tmp_left if height[i] > tmp_left: # current height is greater, update the tmp_left so it could be coundary for upcoming indexes tmp_left = height[i] for i in range(n-1, -1, -1): max_right[i] = tmp_right if height[i] > tmp_right: tmp_right = height[i] res = 0 for i in range(n): if height[i] < min(max_left[i], max_right[i]): res += min(max_left[i], max_right[i])-height[i] return res