Given n
non-negative integers representing an elevation map where the width of each bar is 1
, compute how much water it can trap after raining.
Solutions:
ans = sum {min(left_max,right_max)−height[i]min(left_max,right_max)−height[i] for all elements i} (竖)
= [min(height[current], height[st.top()]) - height[top]] * (current - st.top() - 1) (横)
(1) Brute Force
Time: O(n^2)
(2) Dynamic Programming
save left bar and right bar of each element i into an array
Time: O(n); Space: O(n)
C++:
int trap(vector<int>& height)
{
if(height == null)
return 0;
int ans = 0;
int size = height.size();
vector<int> left_max(size), right_max(size);
left_max[0] = height[0];
for (int i = 1; i < size; i++) {
left_max[i] = max(height[i], left_max[i - 1]);
}
right_max[size - 1] = height[size - 1];
for (int i = size - 2; i >= 0; i--) {
right_max[i] = max(height[i], right_max[i + 1]);
}
for (int i = 1; i < size - 1; i++) {
ans += min(left_max[i], right_max[i]) - height[i];
}
return ans;
}
// https://leetcode.com/problems/trapping-rain-water/solution/
(3) Stack: (calculate in one loop)
the left bar is in the stack after the top and right bar is the first one larger than top
the answer can be calculated in a horizontal way
Time: O(n); Space: O(n)
C++:
int trap(vector<int>& height)
{
int ans = 0, current = 0;
stack<int> st;
while (current < height.size()) {
while (!st.empty() && height[current] > height[st.top()]) {
int top = st.top();
st.pop();
if (st.empty())
break;
int distance = current - st.top() - 1;
int bounded_height = min(height[current], height[st.top()]) - height[top];
ans += distance * bounded_height;
}
st.push(current++);
}
return ans;
}
// https://leetcode.com/problems/trapping-rain-water/solution/
(4) 2 Pointers: (in one iteration)
the water trapped is dependant on the lower one of two side bars
so that if one side bar is larger, update the smaller one when it is lower than the current OR add to ans when larger than the current
Time: O(n); Space: O(1)
C++:
int trap(vector<int>& height)
{
int left = 0, right = height.size() - 1;
int ans = 0;
int left_max = 0, right_max = 0;
while (left < right) {
if (height[left] < height[right]) {
height[left] >= left_max ? (left_max = height[left]) : ans += (left_max - height[left]);
++left;
}
else {
height[right] >= right_max ? (right_max = height[right]) : ans += (right_max - height[right]);
--right;
}
}
return ans;
}
// https://leetcode.com/problems/trapping-rain-water/solution/
Java:
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;
}
// https://leetcode.com/problems/trapping-rain-water/discuss/17391/Share-my-short-solution.