84、求最大的矩形面积

84、求最大的矩阵面积

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

tu
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。

tu

图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

题解

1、暴力


两个柱子间矩形的高由它们之间最矮的柱子决定,因此,我们可以考虑所有两两柱子之间形成的矩形面积,该矩形的高为它们之间最矮柱子的高度,宽为它们之间的距离,这样可以找到所要求的最大面积的矩形。

public class Solution {
   public int largestRectangleArea(int[] heights) {
       int maxarea = 0;
       for (int i = 0; i < heights.length; i++) {
           for (int j = i; j < heights.length; j++) {
               int minheight = Integer.MAX_VALUE;
               // 求[i,j]之间的最矮的高
               for (int k = i; k <= j; k++) {
                   minheight = Math.min(minheight, heights[k]);
               }
                // 更新最大的面积
               maxarea = Math.max(maxarea, minheight * (j - i + 1));
           }
       }
       return maxarea;
   }
}

2、暴力的优化

第一版的暴力重复比较了很多次,考虑用前一对柱子之间的最低高度来求出当前柱子对间的最低高度,来减少比较的次数。

用数学语言来表达

$minheight=\min(minheight, heights(j))$ ,其中, heights(j)是第 j 个柱子的高度

// 优化
public class Solution {
   public int largestRectangleArea(int[] heights) {
       int maxarea = 0;
       for (int i = 0; i < heights.length; i++) {
           int minheight = Integer.MAX_VALUE;// 记录从 i开始的最矮的矩形
           for (int j = i; j < heights.length; j++) {
               // 更新目前为止最矮的矩形
               minheight = Math.min(minheight, heights[j]);
               // 更新目前为止最大的矩形面积
               // 新的值(minheight * (j - i + 1))与旧的值取大的一个
               maxarea = Math.max(maxarea, minheight * (j - i + 1));
           }
       }
       return maxarea;
   }
}
// 链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/zhu-zhuang-tu-zhong-zui-da-de-ju-xing-by-leetcode/

3、分治法

  • 递归分治思想
    • 按照最矮的柱子进行二分
    • 最大矩形位于:
      • 整个柱状图
      • 最矮矩形的左边(子问题)
      • 最矮矩形的右边(子问题)
public class Solution {
   public int largestRectangleArea(int[] heights) {
       return calculateArea(heights,0,heights.length - 1);
   }
    
    private int calculateArea(int[] heights,int start,int end){
        // 递归结束判断
        if (start > end) return 0;
        // 求最矮矩形的下标
        int minIndex = start;
        for (int i = start;i <= end;i++){//耗时
            if (heights[minIndex] > heights[i]){
                minIndex = i;
            }
        }
        // 二分递归
        return Math.max(heights[minIndex]*(end - start + 1),Math.max(calculateArea(heights,start,minIndex - 1),calculateArea(heights,minIndex + 1,end)));
    }
}
// 链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/zhu-zhuang-tu-zhong-zui-da-de-ju-xing-by-leetcode/

4、利用栈

  • 利用栈的特点,用栈存储当前遍历到的矩形的下标
public class Solution {
   public int largestRectangleArea(int[] heights) {
       Stack<Integer> stack = new Stack<>();
       stack.push(-1);
       int maxarea = 0;
       for (int i = 0;i < heights.length;i++) {
           // 循环,直到遇到递增的矩形高度
           while(stack.peek() != -1 && heights[stack.peek()] >= heights[i]) {
               // 更新最大矩形的面积
               maxarea = Math.max(maxarea,heights[stack.pop()]*(i - stack.peek() - 1));
           }
           // 矩形的下标入栈
           stack.push(i);
       }
       while(stack.peek() != -1){
           // 更新最大矩形的面结
           maxarea = Math.max(maxarea,heights[stack.pop()]*(heights.length - stack.peek() - 1));
       }
       return maxarea;
   }
   
}

// 链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/solution/zhu-zhuang-tu-zhong-zui-da-de-ju-xing-by-leetcode/

5、一来一回扫秒——单调栈

  • 3min
class Solution {
    
    
    public int largestRectangleArea(int[] heights) {
        int n=heights.length;
        if(n==0) return 0;
        // 左侧最小矩形的下标存储
        int []leftMin=new int[n];
        // 右侧最小值下标存储
        int []rightMin=new int[n];
        leftMin[0]=-1;
        rightMin[n-1]=n;
        int res=0;
        for(int i=1;i < n;i++) 
        {
            int tmp=i-1;// i-1出的矩形最矮
            // 递增就更新最矮矩形的下标tmp,否则不更新
            while(tmp >= 0 && heights[tmp] >= heights[i])
            {
                tmp = leftMin[tmp];
            }
            // 第一个最矮的矩形的下标
            leftMin[i] = tmp;// heights[i]的左侧扩展极限为tmp
        }

        for(int i=n-2;i >= 0;i--)
        {
            int tmp=i+1;
            while(tmp<n && heights[tmp]>=heights[i])
            {
                tmp=rightMin[tmp];
            }
            rightMin[i]=tmp;// heights[i]的右侧扩展极限为tmp
        }
        // 利用leftmin 和 rightmin不断更新最大的矩形面积
        for(int i = 0;i < n;i++)
        {
            // (rightMin[i]-leftMin[i]-1 矩形长度
            res=Math.max(res,(rightMin[i]-leftMin[i]-1)*heights[i]);
        }
        return res;
    }
}

6、混合解法:排序数组判断,递归更新最大值

  • 1ms 递归
class Solution {
    public int largestRectangleArea(int[] heights) {        
        return helper(heights, 0, heights.length - 1);
    }
    
    private int helper(int[] heights, int start, int end){
        if(start > end){
            return 0;
        }
        if(start == end){
            return heights[start];
        }
        int min = heights[start];
        boolean sorted = true;
        for(int i = start + 1; i <= end; i++){// 求当前区间的最小值。 判断是否是非递减的
            // 更新最矮矩形的高度
            min = Math.min(min, heights[i]);
            if(heights[i - 1] > heights[i]){
                sorted = false;
            }
        }
        if(sorted){// 排好序的直接遍历一遍求最大值
            int max = 0;
            for(int i = start; i <= end; i++){
                max = Math.max(max, heights[i] * (end - i + 1));
            }
            return max;
        }

        int area = min * (end - start + 1);
        int startIndex = start;
        for(int i = start; i <= end; i++){
            if(heights[i] == min){// 当前位置是最小值
                area = Math.max(area, helper(heights, startIndex, i - 1));// 递归
                startIndex = i + 1;
            }
        }
        return Math.max(area, helper(heights, startIndex, end));// 递归
    }
}
``

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com

💰

Title:84、求最大的矩形面积

Count:1.3k

Author:攀登

Created At:2020-07-26, 00:19:44

Updated At:2024-06-15, 15:52:32

Url:http://jiafeimao-gjf.github.io/2020/07/26/84%E3%80%81%E6%B1%82%E6%9C%80%E5%A4%A7%E7%9A%84%E7%9F%A9%E5%BD%A2%E9%9D%A2%E7%A7%AF/

Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.

×

Help us with donation