zoukankan      html  css  js  c++  java
  • LeetCode 84. 柱状图中最大的矩形

    https://leetcode-cn.com/problems/largest-rectangle-in-histogram/

    这个题没有做啥要求,暴力也能过。

    其实这个题有点像接雨水一样,看题解有人用扫描法也做出来了。但是还是用单调栈的方法吧,(明明22天前做出来了,今天却做不出来???)

        public int largestRectangleArea(int[] heights) {
            LinkedList<Integer> stack = new LinkedList<>();
            int max = 0;
            for(int i = 0; i < heights.length; i++){
                while(!stack.isEmpty() && heights[stack.getLast()] > heights[i]){
                    int j = stack.removeLast();
                    max = Math.max(max, heights[j] * (stack.isEmpty()?i:(i-stack.getLast() - 1)));
                }
                stack.addLast(i);
            }
            while(!stack.isEmpty()){
                int j = stack.removeLast();
                max = Math.max(max, heights[j] * (stack.isEmpty()?heights.length:(heights.length-stack.getLast() - 1)));
            }
            return max;
        }

    其实还是很容易理解的,我们维护一个递增栈,如果遇到一个比栈顶元素要小的值,就开始计算最大面积。

    我们把数组下标抽象成一排木板并排,然后数组下标就是木板左下角的坐标。

    遇到一个小的元素,我们就依次计算栈顶元素能维护到的最大面积。

    上图我们第一个遇到递减的情况是数组下标为1的时候,那么我们栈中只有一个元素0,我们把它出栈。

    新面积计算的方法:栈顶元素的木板长度 * (如果栈为空,那么就是当前数组下标,否则就是 当前数组下标- 栈顶元素下标 - 1);

    然后我们去比较max和新面积的大小。

    我们重复这个步骤,直到栈为空,或者栈顶元素比当前下标元素还要小的情况

    当然这种方法有可能会出现2,1,5,6,7,8后面全部都是递增的情况,我们就需要在数组的最后边再添加一个长度为0的木板,由于java传的是数组我不想去复制一次,所以就再扫一次栈好了。

    总的来说,我对做过的题有印象,但是有些题目记忆不是很深刻,这题单调栈和全递增的情况后面我都想出来了,就是没有处理好面积计算的时候栈为空的情况。看来还是得多回忆一下老题。

    看到一个单调栈的总结,复制过来记忆一下。LeetCode上单调栈的问题也很多,像接雨水,最大矩形面积,最大正方形面积这种,这个也是比较考验思维的一种题,希望自己可以多回忆一下。

    // 明确单调栈能够解决的问题

    // 1.找右侧第一个更小 增栈

    // 2.找右侧第一个更大 减栈

    // 3.找左侧第一个更小 增栈

    // 4.找左侧第一个更大 减栈

    2020年9月14日更新


    其实这个题和之前接雨水的两个题一样,都是可以用双指针去完成的。

    我们只需要维护left和right数组即可。

    这里的数组指的是 left[i]:第i个柱子左手第一个比当前柱子小的下标。

            right[i]: 第i个柱子右手第一个比当前柱子小的下标。

    我们计算max的方法就是 (right[i] - left[i] - 1) * height[i]。

    class Solution {
        public int largestRectangleArea(int[] heights) {
            /*
                使用 left 和 right 数组 记录 从 i 左右两边延伸,第一个比 i 位置小的柱子索引位置
                那么第 i 根柱子能组成面积的宽度就是 right[i] - left[i] - 1
            */
            int n = heights.length;
            if(n == 0){
                return 0;
            }
            int[] left = new int[n];
            int[] right = new int[n];
    
            //第一根柱子,左边不存在比它小的
            left[0] = - 1;
            //最后一根柱子,右边不存在比它小的
            right[n - 1] = n;
    
            for(int i = 1; i < n; i++){
                int temp = i - 1;
                while(temp >= 0 && heights[temp] >= heights[i]){
                    temp = left[temp];
                }
                //当上述循环 break 后,  temp 即为左边第一根小于 i 位置的柱子
                left[i] = temp;
            }
    
            for(int i = n - 2; i >= 0; i--){
                int temp = i + 1;
                while(temp < n && heights[temp] >= heights[i]){
                    temp = right[temp];
                }
                //当上述循环 break 后,  temp 即为右边第一根小于 i 位置的柱子
                right[i] = temp;
            }
    
            int maxArea = 0;
            for(int i = 0; i < n; i++){
                int width = right[i] - left[i] - 1;
                maxArea = Math.max(maxArea, heights[i] * width);
            }
            return maxArea;
        }
    }
  • 相关阅读:
    获取与端点的连接
    判断div内滚动条是否在底部
    MVC的使用!
    格式转换解决存取数据安全问题
    JQuery input file 上传图片
    contenteditable 常用的一些CSS !!
    C# 生成Json类型数据
    生成Excel
    生成验证码
    图片水印
  • 原文地址:https://www.cnblogs.com/ZJPaang/p/12991034.html
Copyright © 2011-2022 走看看