单调栈② | Java | LeetCode 接雨水 最大的矩形

42. 接雨水

暴力法

for循环遍历每一个柱子,内层for循环找到左边和右边比它高的柱子
时间复杂度 n^2

优化:添加一个预处理
定义一个数组,存放该柱子右边比他高的柱子是哪一个
再用一个数组,存放该柱子左边比他高的柱子是哪一个

单调栈

单调栈:在每日温度题目中,其要找到右边第一个比他大的温度;适配到本题,就是找到当前柱子左边&右边 第一个比它大的温度

遍历一次就能处理完:当前遍历的元素比栈口元素大的时候,说明栈口柱子右边比它大的那个柱子找到了,它左边比它大的柱子怎么找?在栈中。
在这里插入图片描述

class Solution {
    public int trap(int[] height){
        int size = height.length;

        if (size <= 2) return 0;

        // in the stack, we push the index of array
        // using height[] to access the real height
        Stack<Integer> stack = new Stack<Integer>();
        stack.push(0);

        int sum = 0;
        for (int index = 1; index < size; index++){
            int stackTop = stack.peek();
            if (height[index] < height[stackTop]){
                stack.push(index);
            }else if (height[index] == height[stackTop]){
                // 因为相等的相邻墙,左边一个是不可能存放雨水的,所以pop左边的index, push当前的index
                stack.pop();
                stack.push(index);
            }else{
                //pop up all lower value
                int heightAtIdx = height[index];
                while (!stack.isEmpty() && (heightAtIdx > height[stackTop])){
                    int mid = stack.pop();

                    if (!stack.isEmpty()){
                        int left = stack.peek();

                        int h = Math.min(height[left], height[index]) - height[mid];
                        int w = index - left - 1;
                        int hold = h * w;
                        if (hold > 0) sum += hold; //加不加大于0都一样
                        stackTop = stack.peek();
                    }
                }
                stack.push(index);
            }
        }

        return sum;
    }
}
  • 自己再做了一遍
class Solution {
    public int trap(int[] height) {
        if(height.length <= 2) {
            return 0;
        }

        Stack<Integer> st = new Stack<>(); //存的是下标
        st.push(0);

        int sum = 0;
        for(int i=1; i<height.length; i++) {
            // i 下标  height[i]值
            // height[st.peek()]  height[st.pop()]


            if(height[i] < height[st.peek()]) {
                st.push(i);
            } else if(height[i] == height[st.peek()]) {
                st.pop();
                st.push(i); //虽然值是一样的,但下标不一样
            } else { //发现凹槽了
                // int stackTop = st.peek();
                int right = i; //凹槽右侧高度
                while(!st.empty() && height[right] > height[st.peek()]) {
                    int mid = st.pop();//凹点

                    if(!st.empty()) {
                        int left = st.peek();
                        int w = right-left-1;
                        int h = Math.min(height[left], height[right]) - height[mid];
                        int hold = h*w;
                        sum += hold;

                    }
                }
                st.push(i);
                //体积 = w * h 
            }
        }
        return sum;
    }
}

双指针

与单调栈不同的是,双指针求体积求的是 竖向的体积

class Solution {
    public int trap(int[] height) {
        int len = height.length;
        if(len <= 2) return 0;

        int[]maxLeft = new int[len];
        int[]maxRight = new int[len];

        maxLeft[0] = height[0];
        for(int i=1; i<len; i++) {
            maxLeft[i] = Math.max(height[i], maxLeft[i-1]);
        }

        maxRight[len-1] = height[len-1];
        for(int i=len-2; i>=0; i--) {
            // maxLeft[i] = Math.max(height[i], maxLeft[i-1]);
            maxRight[i] = Math.max(height[i],maxRight[i+1]);
        }

        int sum = 0;
        for(int i=0; i<len; i++) {
            int h = Math.min(maxLeft[i],maxRight[i]) - height[i];
            if(h>0) sum+=h; // h*1
        }
        return sum;
    }
}

84.柱状图中最大的矩形

emmm 和接雨水到底哪里一样了???

暴力法 双指针

遍历每一根柱子,向左向右找比它小的边界,算出面积并求最大
优化:两个数组,一个存放i左边比他矮的,一个存放i右边

单调栈

写法不一样了,栈中元素 从栈顶到栈底要 从大到小。

遍历一次就能处理完:当前遍历的元素比栈口元素小的时候,说明栈口柱子右边比它小的那个柱子找到了,它左边比它小的柱子怎么找?在栈中。

  • 首尾补0
    尾补0:[2,4,6,8]
    首补0:[8,6,4,2]
class Solution {
    public int largestRectangleArea(int[] heights) {
        int[]newHeight = new int[heights.length+2];
        for(int i=1; i<=heights.length; i++) {
            newHeight[i] = heights[i-1];
        }
        heights = newHeight; //重定向
        Stack<Integer> st = new Stack<Integer>();
        st.push(0);
        int res=0;
        for(int i=1; i<heights.length; i++) {
            
            if(heights[i]>heights[st.peek()]) {
                st.push(i);
            } else if(heights[i] == heights[st.peek()]) {
                st.pop();
                st.push(i);
            } else {
                //栈可能为空吗?
                while(heights[i] < heights[st.peek()]) {
                    int mid = st.peek();
                    st.pop();
                    int left = st.peek();
                    int right = i;
                    int w = right - left - 1;
                    int h = heights[mid];
                    res = Math.max(res, w * h);
                }
                st.push(i);
            }

        }
        return res;
    }
}

单调栈最核心的其实是栈顶元素

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值