84. 柱状图中最大的矩形(单调栈)

package com.heu.wsq.leetcode.monotone_stack;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * 84. 柱状图中最大的矩形
 * @author wsq
 * @date 2020/12/26
 * 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
 * 求在该柱状图中,能够勾勒出来的矩形的最大面积。
 * 由于这道题有图,大家可以访问下方的连接直接去查看
 * 以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
 * 图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
 *
 * 示例:
 * 输入: [2,1,5,6,2,3]
 * 输出: 10
 *
 * 链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram
 */
public class LargestRectangleArea {
    /**
     * 暴力解法
     * 外侧遍历以每一个矩形高度为底边,然后向左右扩展满足自己条件的宽
     * @param heights
     * @return
     */
    public int largestRectangleArea(int[] heights){
        int n = heights.length;
        int maxArea = 0;
        for (int i = 0; i < n; i++){
            int width = 1;
            for(int j = i + 1; j < n; j++){
                if (heights[j] >= heights[i]){
                    width++;
                }else{
                    break;
                }
            }

            for (int j = i - 1; j >= 0; j--){
                if (heights[j] >= heights[i]){
                    width++;
                }else{
                    break;
                }
            }
            maxArea = Math.max(width * heights[i], maxArea);
        }
        return maxArea;
    }

    /**
     * 暴力解法的缺点就是在寻找左右两边"第一个"比当前矩阵低的位置不够效率,时间复杂度为O(n)
     * 采用空间换时间的思想,当遇见寻找左右两边 "第一个" 大于或小于 当前元素的元素位置时,我们首先要想到去运用单调栈的思想
     * @param heights
     * @return
     */
    public int largestRectangleArea2(int[] heights){
        int n = heights.length;

        if (n == 0){
            return 0;
        }

        if (n == 1){
            return heights[0];
        }
        Deque<Integer> stack = new ArrayDeque<>();
        int area = 0;
        for (int i = 0; i < n; i++){
            while (!stack.isEmpty() && heights[stack.peekLast()] > heights[i]){
                int height = heights[stack.removeLast()];
                int width;
                if (stack.isEmpty()){
                    width = i;
                }else{
                    width = i - stack.peekLast() -1;
                }
                area = Math.max(area, height * width);
            }
            stack.addLast(i);
        }
        while (!stack.isEmpty()){
            int height = heights[stack.removeLast()];
            int width;
            if (stack.isEmpty()){
                width = n;
            }else{
                width = n - stack.peekLast() - 1;
            }
            area = Math.max(area, width * height);
        }
        return area;
    }

    /**
     * 哨兵和单调栈通常一起使用,增加虚拟节点,将需要特殊讨论的位置一般化,降低问题的逻辑复杂度,进一步提高算法的效率
     * 增加哨兵,降低逻辑的复杂度。
     * @param heights
     * @return
     */
    public int largestRectangleArea3(int[] heights){
        int n = heights.length;
        if (n == 0){
            return 0;
        }
        if (n == 1){
            return heights[0];
        }
        Deque<Integer> stack = new ArrayDeque<>();
        int area = 0;
        // 设置哨兵
        int[] newHeights = new int[n + 2];
        System.arraycopy(heights, 0, newHeights, 1, n);
        stack.addLast(newHeights[0]);
        for (int i = 1; i < n + 2; i++){
            while(newHeights[stack.peekLast()] > newHeights[i]){
                int height = newHeights[stack.removeLast()];
                int width = i - stack.peekLast() - 1;
                area = Math.max(area, height * width);
            }
            stack.addLast(i);
        }
        return area;
    }

    public static void main(String[] args) {
        int[] heights = {2, 1, 5, 6, 2, 3};
        LargestRectangleArea lr = new LargestRectangleArea();
        int ans = lr.largestRectangleArea3(heights);
        System.out.println(ans);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值