题目:存储雨水
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.
Example:
Input: [0,1,0,2,1,0,1,3,2,1,2,1] Output: 6
方法一:暴力破解法
Intuition
Do as directed in question. For each element in the array, we find the maximum level of water it can trap after the rain, which is equal to the minimum of maximum height of bars on both the sides minus its own height.
Algorithm
- Initialize ans=0ans=0
- Iterate the array from left to right:
- Initialize left_max=0 and right_max=0
- Iterate from the current element to the beginning of array updating:
- left_max=max(left_max,height[j])
- Iterate from the current element to the end of array updating:
- right_max=max(right_max,height[j])
Add min(left_max,right_max)−height[i] to ans
-
Time complexity: O(n^2) For each element of array, we iterate the left and right parts.
-
Space complexity: O(1) extra space.
每次求得 位置 i 的蓄水量,left,right为左右遮挡物
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if(n == 0)
return 0;
int res = 0;
for(int i = 0; i < n; i++)
{
int lm = 0, rm = 0;
for(int j = 0; j < i; j++)
{
lm = max(lm,height[j]);
}
for(int j = i + 1; j < n; j++)
{
rm = max(rm,height[j]);
}
int swater = min(lm,rm) - height[i];
if(swater > 0)
res += swater;
}
return res;
}
};
方法二:动态规划
Algorithm
- Find maximum height of bar from the left end upto an index i in the array left_max.
- Find maximum height of bar from the right end upto an index i in the array right_max.
- Iterate over the height array and update ans:
- Add min(left_max[i],right_max[i])−height[i] to ans
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
if(n == 0) return 0;
int ans = 0;
vector<int> lm(n),rm(n);
lm[0] = height[0];
for(int i = 1; i < n; i++)
{
lm[i] = max(lm[i - 1],height[i]);
}
rm[n-1] = height[n - 1];
for(int i = n - 2; i >= 0; i--)
{
rm[i] = max(rm[i + 1],height[i]);
}
for(int j = 1; j < n; j++)
{
ans += min(lm[j],rm[j]) - height[j];
}
return ans;
}
};
方法三:使用栈
- Use stack to store the indices of the bars.
- Iterate the array:
- While stack is not empty and height[current]>height[st.top()]
- It means that the stack element can be popped. Pop the top element as top.
- Find the distance between the current element and the element at top of stack, which is to be filled. distance=current−st.top()−1
- Find the bounded_height=min(height[current],height[st.top()])−height[top]
- Add resulting trapped water to answer ans+=distance×bounded_height
- Push current index to top of the stack
- Move current to the next position
- While stack is not empty and height[current]>height[st.top()]
class Solution {
public:
int trap(vector<int>& height) {
int n = height.size();
int ans = 0,cur = 0;
stack<int> stk;
while(cur < n)
{
while(!stk.empty() && height[cur] > height[stk.top()])
{
int top = stk.top();
stk.pop();
if(stk.empty())
break;
int distance = cur - stk.top() - 1;
int bound = min(height[cur],height[stk.top()]) - height[top];
ans += distance * bound;
}
stk.push(cur);
cur++;
}
return ans;
}
};
方法四: 双指针
- Initialize left pointer to 0 and right pointer to size-1
- While left<right, do:
- If height[left] is smaller than height[right]
- If height[left]≥left_max, update left_max
- Else add left_max−height[left] to ans
- Add 1 to left.
- Else
- If height[right]≥right_max, update right_max
- Else add right_max−height[right] to ans
- Subtract 1 from right
- If height[left] is smaller than height[right]
class Solution {
public:
int trap(vector<int>& height) {
int left = 0, right = height.size() - 1;
int ans = 0;
int lm = 0, rm = 0;
while(left < right)
{
if(height[left] < height[right])
{
if(height[left] >= lm)
{
lm = height[left];
}
else
{
ans += lm - height[left];
}
++left;
}
else
{
if(height[right] >= rm)
{
rm = height[right];
}
else
{
ans += rm - height[right];
}
--right;
}
}
return ans;
}
};