题目链接:leetcode.
能隐约感觉到是动态规划,但具体思路不知道
left[i]
记录i
左边能取到的最大值,right[i]
记录i
右边能取到的最大值,那么i
处能接到的雨水就是左右两边的较小值与它自己高度的差值
O(n) O(n)
/*
执行用时:4 ms, 在所有 C++ 提交中击败了93.86%的用户
内存消耗:13.9 MB, 在所有 C++ 提交中击败了53.36%的用户
*/
class Solution {
public:
int trap(vector<int>& height) {
int N = height.size();
if(N < 2)
return 0;
vector<int> left(N);
vector<int> right(N);
left[0] = height[0];
right[N - 1] = height[N - 1];
for(int i = 1;i < N;++i)
{
left[i] = max(left[i - 1], height[i]);
}
for(int i = N - 2;i >= 0;--i)
{
right[i] = max(right[i + 1], height[i]);
}
int ans = 0;
for(int i = 0;i < N;++i)
{
if(height[i] < left[i] && height[i] < right[i])
{
ans += min(left[i], right[i]) - height[i];
}
}
return ans;
}
};
单调栈的做法,栈中递减,碰到大的,就能在栈顶组成一个“大小大”的组合,就可以接雨水了
能接的那个小矩形,宽为栈顶上下两个数字的下标差,长为两个数字较小值与栈顶的差
为了方便起见,栈中保存数字的下标
O(n) O(n)
/*
执行用时:8 ms, 在所有 C++ 提交中击败了69.36%的用户
内存消耗:14 MB, 在所有 C++ 提交中击败了36.37%的用户
*/
class Solution {
public:
int trap(vector<int>& height) {
int N = height.size();
if(N < 2)
return 0;
stack<int> stk;
int ans = 0;
for(int i = 0;i < N;++i)
{
if(!stk.empty())
{
if(height[i] >= height[stk.top()])
{
while(!stk.empty() && height[i] > height[stk.top()])
{
int index = stk.top();
stk.pop();
if(!stk.empty())
ans += (min(height[i], height[stk.top()]) - height[index]) * (i - stk.top() - 1);
}
}
}
stk.push(i);
}
return ans;
}
};
不用存储左右两边的最大值,将动态规划的空间复杂度降为O(1)
我们可以认为如果一端有更高的条形块(例如右端),积水的高度依赖于当前方向的高度(从左到右)。当我们发现另一侧(右侧)的条形块高度不是最高的,我们则开始从相反的方向遍历(从右到左)。
用两个变量存储左右的最大值,双指针进行移动,计算矩形面积
/*
执行用时:8 ms, 在所有 C++ 提交中击败了69.36%的用户
内存消耗:13.8 MB, 在所有 C++ 提交中击败了80.21%的用户
*/
class Solution {
public:
int trap(vector<int>& height) {
int N = height.size();
if(N < 2)
return 0;
int left = 0, right = N - 1;
int left_Max = height[0], right_Max = height[N - 1];
int ans = 0;
while(left < right)//等于就跳出了
{
if(left_Max < right_Max)
{
//依赖左边的端点
if(height[left] < left_Max)
ans += left_Max - height[left];
left++;
left_Max = max(left_Max, height[left]);
}
else
{
//依赖右边的端点
if(height[right] < right_Max)
ans += right_Max - height[right];
right--;
right_Max = max(right_Max, height[right]);
}
}
return ans;
}
};