一. 题目
二. 思路
1. 左边界找最大右边界
若右边有>=当前值的,则找到右边第一个>=左边界的右边界。
若右边没有>=当前左边界的,则找到右边<左边界的最大的一个值。
要预处理rmax[i]:表示i右边的最大值,不含i
时间复杂度O(n)、空间复杂度O(n)
2. dp
3. 双指针
三. 代码
1. 左边界找最大右边界
class Solution
{
static final int N = (int) 2e4 + 10;
int[] rmax = new int[N];
public int trap(int[] height)
{
int n = height.length;
int maxv = height[n - 1];
rmax[n - 1] = -1;
for (int i = n - 2; i >= 0; --i)
{
rmax[i] = maxv;
maxv = Math.max(maxv, height[i]);
}
int ans = 0;
for (int i = 0; i < n; )
if (rmax[i] >= height[i])//右边存在>=左边界的值
{
int lv = height[i++];//i要++, 因为刚开始height==lv
while (i < n && height[i] < lv)//到达右边界停止
ans += lv - height[i++];
} else
{
int j = i;
while (j < n && rmax[i] == rmax[j]) ++j;//右边最大值停止
while (++i < n && i < j) ans += height[j] - height[i];//i要先+,否则会hj-hi第一次计算是个负数
}
return ans;
}
}
2. dp
class Solution
{
static final int N = (int) 2e4 + 10;
int[] lmax = new int[N], rmax = new int[N];
public int trap(int[] height)
{
int n = height.length;
lmax[0] = height[0];
for (int i = 1; i < n; ++i) lmax[i] = Math.max(lmax[i - 1], height[i]);
rmax[n - 1] = height[n - 1];
for (int i = n - 2; i >= 0; --i) rmax[i] = Math.max(rmax[i + 1], height[i]);
int ans = 0;
for (int i = 0; i < n; ++i)
ans += Math.min(lmax[i], rmax[i]) - height[i];
return ans;
}
}
3. 双指针
class Solution
{
public int trap(int[] height)
{
int ans = 0;
int lmax = 0, rmax = 0;
for (int l = 0, r = height.length - 1; l < r; )//不用l==r是因为,最终相遇位置一定是一个最高点
{
lmax = Math.max(lmax, height[l]);
rmax = Math.max(rmax, height[r]);//若h[l]<h[r]必有lmax<rmax,因为rmax至少为h[r],且只有h[l]<h[r]时l才会右移
if (height[l] < height[r]) ans += lmax - height[l++];
else ans += rmax - height[r--];
}
return ans;
}
}