前后缀分解
class Solution {
public int trap(int[] height) {
int n = height.length;
int[] preMax = new int [n];
preMax[0] = height[0];
for (int i = 1; i < n; i++) {
preMax[i] = Math.max(preMax[i - 1], height[i]);
}
int[] sufMax = new int [n];
sufMax[n - 1] = height[n - 1];
for (int i = n-2; i >= 0; i--) {
sufMax[i] = Math.max(sufMax[i + 1], height[i]);
}
int ans = 0;
for( int i = 0; i < n; i++) {
ans += Math.min(preMax[i], sufMax[i]) - height[i];
}
return ans;
}
}
双指针
- preMax和sufMax分别为前后缀最大值,那就意味随着指针的移动,preMax后面维护的值肯定比最开始都大,sufMax前面维护的值也比后面都大,所以在sufMax和preMax进行比较的时候,哪一个比较小一定会一直小,所以最后又是以小的那个值为主和当前位置的height进行比较
class Solution {
public int trap(int[] height) {
int ans = 0;
int preMax = 0;
int sufMax = 0;
int left = 0;
int right = height.length - 1;
while (left < right) {
preMax = Math.max(preMax, height[left]);
sufMax = Math.max(sufMax, height[right]);
if (sufMax < preMax) {
ans += sufMax - height[right];
right--;
} else {
ans += preMax - height[left];
left++;
}
}
return ans;
}
}
单调栈
class Solution {
public int trap(int[] height) {
int ans = 0;
Deque<Integer> st = new ArrayDeque<>();
for (int i = 0; i < height.length; i++) {
int h = height[i];
//临界条件是找到上一个更大的元素,只要比h小就会形成一个坑,单调栈就是横向计算面积填坑
//peek()方法元素只显示不弹出栈
//可以先想象成一个凹字,最右边就是i位置,中间是bottomH凹下去的这一块,最左边是left
while (!st.isEmpty() && height[st.peek()] < h) {
int bottomH = height[st.pop()];
if (st.isEmpty()) {
break;
}
int left = st.peek();
int dh = Math.min(height[left],height[i]) - bottomH;
ans += dh * (i - left - 1);
}
st.push(i);
}
return ans;
}
}