42 接雨水

7 阅读1分钟

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;
    }
}