思路:
思路1:
前后缀,先分别算出当前位置前缀的最大值和当前位置后缀的最大值,包括当前位置。然后再算出每个位置对最终答案的贡献,贡献等于前后缀最大值中最小的哪一个减去当前位置的高度。
思路2:
双指针,左指针维护前缀的最大值,右指针维护后缀的最大值,包括当前位。然后如果前缀最大值小于后缀最大值,因为后缀的最大值只可能更大,不可能更小,所以左指针位置的贡献可以算出来了,同理右指针也一样。
思路3:
单调栈,从左到右单调递减栈,找到第一个大于栈顶的元素,栈顶依次出栈,计算贡献。左边界是栈顶的下一个元素,右边界是当前元素,还要乘以跨度。
代码:
思路1:
class Solution {
public int trap(int[] height) {
int n = height.length;
int[] pre = new int[n];
int[] suf = new int[n];
pre[0] = height[0];
suf[n - 1] = height[n - 1];
for(int i = 1; i < n; i++) {
pre[i] = Math.max(pre[i - 1], height[i]);
}
for(int i = n - 2; i >= 0; i--) {
suf[i] = Math.max(suf[i + 1], height[i]);
}
int ans = 0;
// 计算每个位置的贡献
for(int i = 0; i < n; i++) {
ans += Math.min(pre[i], suf[i]) - height[i];
}
return ans;
}
}
思路2:
class Solution {
public int trap(int[] height) {
int n = height.length;
int l = 0;
int r = n - 1;
int leftHeight = 0;
int rightHeight = 0;
int ans = 0;
while(l < r) {
leftHeight = Math.max(leftHeight, height[l]);
rightHeight = Math.max(rightHeight, height[r]);
if(leftHeight < rightHeight) {
ans += leftHeight - height[l];
l++;
}
else {
ans += rightHeight - height[r];
r--;
}
}
return ans;
}
}
思路3:
class Solution {
public int trap(int[] height) {
int n = height.length;
int ans = 0;
Deque<Integer> stack = new ArrayDeque<>();
for(int i = 0; i < n; i++) {
while(!stack.isEmpty() && height[i] > height[stack.peek()]) {
int t = stack.pop();
if(!stack.isEmpty()) {
int q = Math.min(height[i], height[stack.peek()]) - height[t];
ans += q*(i - stack.peek() - 1);
}
}
stack.push(i);
}
return ans;
}
}
参考: