[LeetCode 困难 单调栈]84. 柱状图中最大的矩形

题目描述

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

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

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

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

示例:

输入: [2,1,5,6,2,3]
输出: 10

暴力算法 (超时)

复杂度分析:

时间复杂度:O(N^2) 这里 NN 是输入数组的长度。
空间复杂度:O(1)。
算每个正方形的横竖的最大面积

public class Solution {
    public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        if(len == 0) return 0;
        
        int res = 0;
        for(int i = 0; i < len; i++){
            int curHeight = heights[i];
            int left = i;
            int right = i;

            while(left >0 && heights[left - 1] >= curHeight){
                left--;
            }

            while(right < len-1 && heights[right + 1] >= curHeight){
                right++;
            }

            int width = right - left + 1;
            int area = width * curHeight;
            res = Math.max(res, area);
        }

        return res;
    }
}

单调栈

复杂度分析:

时间复杂度:O(N),输入数组里的每一个元素入栈一次,出栈一次。
空间复杂度:O(N),栈的空间最多为 N。

import java.util.*;

public class Solution {

    public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        if (len == 0) return 0;
        if (len == 1) return heights[0];

        //单调栈的思路就是用栈实现单调递增 
        //有比要放进去的大的 就弹出来 弹到没有比要放进去的大了 就把要放进去的放进去
        int res = 0;
        Deque<Integer> stack = new ArrayDeque<>(len);
        for (int i = 0; i < len; i++) {
            // 这个 while 很关键,因为有可能不止一个柱形的最大宽度可以被计算出来
            while (!stack.isEmpty() && heights[i] < heights[stack.peekLast()]) {
                int curHeight = heights[stack.pollLast()];
                while (!stack.isEmpty() && heights[stack.peekLast()] == curHeight) {
                    stack.pollLast();
                }

                int curWidth;
                if (stack.isEmpty()) {
                    //柱子的宽度 (栈为空 就是第一个放进去的时候)
                    curWidth = i;
                } else {
                    //现在柱子的宽度 = 挨着这根柱子的比它大的柱子 i - (最大数的位子) - 第i根柱子 中间的就是可以组成正方形的
                    curWidth = i - stack.peekLast() - 1;
                }
                // System.out.println(curHeight+ "    " +curWidth);
                res = Math.max(res, curHeight * curWidth);
            }
            stack.addLast(i);
        }

        //来计算剩下的在栈内的 按柱高从大到小来找柱子面积
        while (!stack.isEmpty()) {
            int curHeight = heights[stack.pollLast()];
            while (!stack.isEmpty() && heights[stack.peekLast()] == curHeight) {
                stack.pollLast();
            }

            int curWidth;
            if (stack.isEmpty()) {
                //最低的肯定是所有都能满足 所以宽是len
                curWidth = len;
            } else {
                //宽度 = 长度 - 下一个大的柱子的位置
                curWidth = len - stack.peekLast() - 1;
            }
            // System.out.println(curHeight+ "    " +curWidth);
            res = Math.max(res, curHeight * curWidth);
        }
        return res;
    }
}


*****单调栈 + 哨兵

复杂度分析:

时间复杂度:O(N),输入数组里的每一个元素入栈一次,出栈一次。
空间复杂度:O(N),栈的空间最多为 N。

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

public class Solution {

    public int largestRectangleArea(int[] heights) {
        int len = heights.length;
        if (len == 0) {
            return 0;
        }

        if (len == 1) {
            return heights[0];
        }

        int res = 0;

        int[] newHeights = new int[len + 2];
        newHeights[0] = 0;
        System.arraycopy(heights, 0, newHeights, 1, len);
        newHeights[len + 1] = 0;
        len += 2;
        heights = newHeights;

        Deque<Integer> stack = new ArrayDeque<>(len);
        // 先放入哨兵,在循环里就不用做非空判断
        stack.addLast(0);
        
        for (int i = 1; i < len; i++) {
            while (heights[i] < heights[stack.peekLast()]) {
                int curHeight = heights[stack.pollLast()];
                int curWidth = i - stack.peekLast() - 1;
                res = Math.max(res, curHeight * curWidth);
            }
            stack.addLast(i);
        }
        return res;
    }

}

单调栈题目

  1. 接雨水(困难) 暴力解法、优化、双指针、单调栈
  2. 每日温度(中等) 暴力解法 + 单调栈
  3. 下一个更大元素 I(简单) 暴力解法、单调栈
  4. 去除重复字母(困难) 栈 + 哨兵技巧(Java、C++、Python)
  5. 股票价格跨度(中等) 「力扣」第 901 题:股票价格跨度(单调栈)
  6. 移掉K位数字
  7. 最短无序连续子数组
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值