LeetCode HOT100 - 接雨水
不难想到一个点能否接到水,以及能接到多少水是和它左侧以及右侧第一个大于它的元素是有关的
它的贡献是对应的横向的矩形
这个信息的处理可以用单调栈来做
若记为 pre 和 suf , 那么这个点的贡献是
if (pre[i] == -1 || suf[i] == -1) {
continue;
}
ans += (min(a[pre[i]], a[suf[i]]) - a[i]) * (pre[i] - suf[i] - 1);
但如果我们真这样两个方向都维护第一个大于的话,实际上会有一些问题,即重复计算的问题
例如示例中的下标 4, 6 ,对应的那个矩形会被计算两次
解决的方法就是高度相同的怎么保留一个,或者只让一个产生贡献,于是,我们可以找左侧第一个大于的时候,换成大于等于,这样只有这个区间中第一个这个高度的产生贡献,像是示例中的 4
class Solution {
public:
int trap(vector<int>& a) {
int n = a.size();
vector<int> pre(n, -1);
vector<int> suf(n, -1);
vector<int> st;
{
for (int i = 0; i < n; i++) {
while (!st.empty() && a[st.back()] < a[i]) {
suf[st.back()] = i;
st.pop_back();
}
st.emplace_back(i);
}
}
st.clear();
{
for (int i = n - 1; i >= 0; i--) {
while (!st.empty() && a[st.back()] <= a[i]) {
pre[st.back()] = i;
st.pop_back();
}
st.emplace_back(i);
}
}
int ans = 0;
for (int i = 0; i < n; i++) {
if (pre[i] == -1 || suf[i] == -1) {
continue;
}
ans += (min(a[pre[i]], a[suf[i]]) - a[i]) * (suf[i] - pre[i] - 1);
// cout << i << " " << pre[i] << ' ' << suf[i] << '\n';
// cout << (min(a[pre[i]], a[suf[i]]) - a[i]) * (suf[i] - pre[i] - 1) << '\n';
}
return ans;
}
};
解法或者题解好像挺多的,有图应该会方便理解一些
存一下链接,下次看,好像还有类似于动规这种阴影面积的,感觉也挺巧妙的
https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc
https://leetcode.cn/problems/trapping-rain-water/solutions/9112/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-8
https://leetcode.cn/problems/trapping-rain-water/solutions/185678/trapping-rain-water-by-ikaruga

浙公网安备 33010602011771号