初始思路:单调栈
这是个不太寻常的单调栈,但也是可以做的。思路是,如果一直递减,就留着。如果递增,看看左边有没有护着的,有就计数,没有就继续往左走。这样能循环的不断加较低的水坑,挺难想的其实。
class Solution:
def trap(self, height: List[int]) -> int:
if not height: return 0
stack = []
ret = 0
for i, h in enumerate(height):
while stack and h >= height[stack[-1]]:
if len(stack) > 1 and height[stack[-1]] <= height[stack[-2]]:
ht = min(h, height[stack[-2]]) - height[stack[-1]]
wd = i - stack[-2] - 1
ret += ht*wd
stack.pop()
stack.append(i)
return ret
解法二:双指针
这个思路真的是太强了。。
首先咱们理一下思路,只考虑随意一个柱子,它能接的雨水量取决于左边所有柱子的最大值和右边所有柱子最大值的最小者。所以这个题用单调栈做比较费劲就是因为不是仅维护一个最小值所在区间,而是要同时考虑两侧。
这个题用双指针做,从两边开始(最靠边的接不到水),分别维护左边最大值和右边最大值。如果有一方较小,那么这一方的接水量已定,因为右边最大值只会更大,不会更小。如果两边最大值相等,任意移动一个即可。如果都移动,需要考虑二者是否重合,没必要,代码如下:
class Solution {
public:
int trap(vector<int>& height) {
int ret = 0;
int n = height.size();
if(n < 3)return 0;
int l = 1, r = n-2;
int lmax = height[0], rmax = height[n-1];
while(l<=r)
{
if(lmax > rmax)
{
ret += max(0, rmax-height[r]);
rmax = max(rmax, height[r--]);
}
else
{
ret += max(0, lmax-height[l]);
lmax = max(lmax, height[l++]);
}
}
return ret;
}
};