42. 接雨水 - 力扣(LeetCode) 方法一 :预处理两边的最大值 法二:根据大小来决定,可以先用左边的,也可以先用右边的。所以可以使用双指针实现O(1)的空间复杂度 法三:用栈
class Solution {
public int trap(int[] height) {
/* 方法一 :预处理两边的最大值
int max = 0;
int[] leftmax = new int[height.length];
int[] rightmax = new int[height.length];
//先找遍历赋值给每根柱子左边的最大值
for(int i = 1; i < height.length; i++) {
max = Math.max(max,height[i-1]);
leftmax[i] = max;
}
//遍历赋值给每根柱子右边的最大值
max = 0;
for(int i = height.length-2; i >=0 ; i--) {
max = Math.max(max,height[i+1]);
rightmax[i] = max;
}
//每根柱子上的水的高度 = min(leftmax[i],rightmax[i]) - height[i]
int ans = 0;
for(int i = 1; i < height.length-1; i++) {
int min = Math.min(leftmax[i],rightmax[i]);
if(min > height[i])
ans += min - height[i];
}
return ans;
*/
/*方法二:双指针
int leftmax = 0, rightmax= 0;
int l = 1,r = height.length-2;
int ans = 0;
for(int i = 1; i < height.length - 1; i++) {
if(height[l-1] < height[r+1]) { //可以理解为结果要根据两边最高的两个中相比矮的那一个,然后淘汰比较短的柱子,下一位
leftmax = Math.max(leftmax,height[l-1]);
int min = leftmax;
if(height[l] < min) {
ans += min - height[l];
}
l++;
}
else {
rightmax = Math.max(rightmax,height[r+1]);
int min = rightmax;
if(height[r] < min) {
ans += min - height[r];
}
r--;
}
}
*/
//方法三: 单调栈
//如果当前柱子比栈顶小就放进去
//如果当前柱子比栈顶大,就弹出栈顶,并计算水的体积(要考虑两者之间的横向距离)循环往复,直到栈为空或当前柱子比栈顶小。然后把当前柱子压入栈
int ans = 0;
Stack<Integer> st = new Stack<>();
for(int i = 0; i < height.length; i++) {
while(!st.isEmpty() && height[i] > height[st.peek()]) {
int idx = st.peek();
st.pop();
if(st.isEmpty()) {
break;
}
int min = Math.min(height[i],height[st.peek()]);
// System.out.println(st.peek() + " " + i + " 中间:"+ idx + " " +(min-height[idx])*(i-st.peek()-1));
// ans += (min-height[idx])*(i-idx);
ans += (min-height[idx])*(i-st.peek()-1);
}
st.push(i);
}
return ans;
}
}