leetcode84- 柱状图中最大的矩形(三种思路:暴力,单调栈+哨兵(详解),分治)

  • 介绍
    • 题目
  • 解题思路
    • 解法一:暴力向两边搜索
    • 解法二:单调栈
      • 画图演示
      • 宽度计算:
    • 解法三:单调栈+哨兵
    • 解法四:分治,这是最快的方法
  • 代码
    • 解法一:暴力
    • 解法二:单调栈
    • 解法三:单调栈+哨兵
    • 解法四:动态规划

介绍

我的LeetCode主页,一题一题解

标签:贪心

84. 柱状图中最大的矩形
难度 困难

84. 柱状图中最大的矩形
https://leetcode-cn.com/problems/largest-rectangle-in-histogram/

题目

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

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

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

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

示例:

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



解题思路

虽然我也进行的单调栈的详解,但是看我的之前可以看看liweiwei1419大佬的题解以及官方题解的视频


解法一:暴力向两边搜索

对该柱子两边进行遍历,寻找以当前高度可以取得的最大面积,看一眼应该就懂了


解法二:单调栈

构建一个递增的单调栈,因为:

  • 如果后一个柱高度比目前柱更高,说明矩形面积还有增加的可能性
  • 如果后一个柱高度比目前柱更矮,说明已经没有增长空间了,可以出栈计算能形成的最大面积

画图演示

  1. heights[0] 因为是第一个所以直接入栈

  2. 遍历到heights[1]比heights[0]更矮,计算可得heights[0]的最大面积,然后将heights[1]入栈

  3. 遍历到heights[2],发现heights[1]更矮,因此heights[2]直接入栈

  4. 遍历到heights[3],发现heights[2]更矮,因此heights[3]也直接入栈

  5. 遍历到heights[4],发现当前栈顶元素heights[3]更高,则将其出栈,并计算其最大面积

  6. 继续比较会发现当前栈顶元素heights[2]还是比heights[4]大,继续出栈并计算最大面积

  7. 遍历到最后一个heights[5],发现heights[4]更矮,heights[4]入栈

  8. 遍历已经到最末尾了,将heights[5]也入栈,准备将栈内元素全部清空了

宽度计算:

宽度计算全部发生在出栈的情况下,并且有两个情况:

  1. 栈内没有其他元素了,那么一直到heights[0]都可以在当前高度下形成矩形
  2. 栈内还有其他元素,那么直到次栈顶元素,这段区间都是可以形成矩形的

解法三:单调栈+哨兵

因为在解法二中考虑了栈空与结尾栈不为空的情况,导致了造成了冗余,所以就在输入数组的两端加上两个高度为0的柱子,使之为**“哨兵”**

有了哨兵之后:

  1. 数组第一位的哨兵会使栈一定不会为空
  2. 数组最后位的哨兵会使前面全部有高度的柱出栈

从而可以保证将全部的柱能形成的高度全部计算一遍


解法四:分治,这是最快的方法

将数组分为最矮柱左边的部分与最矮柱右边的部分
然后三个中求最大

  1. 最大宽度*最小高度
  2. 最矮柱左边能形成的最大面积
  3. 最矮柱右边能形成的最大面积

同时对数组段是否递增进行判断,如果一旦是单调递增,那么最大的面积毫无疑问就是最矮柱高度*当前宽度



代码

解法一:暴力

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 hight = heights[i];// 向左找int left = i;while (left > 0 && heights[left - 1] >= hight) {left--;}// 向右找int right = i;while (right < len - 1 && heights[right + 1] >= hight) {right++;}int sum = right - left + 1;res = Math.max(res, sum * hight);}return res;}
}

这么慢的吗…


解法二:单调栈

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 width;if (stack.isEmpty()) {//栈空说明直到最开始的一个柱形都能构成矩形width = i;} else {//一般情况,在于下一个栈内元素之间都能构成矩形width = i - stack.peekLast() - 1;}res = Math.max(res, curHeight * width);}stack.addLast(i);}// 如果站内没有清空,那么就循环弹出while (!stack.isEmpty()) {// 操作和上面一样,但是i变成了len,因为遍历已经结束了int curHeight = heights[stack.pollLast()];while (!stack.isEmpty() && heights[stack.peekLast()] == curHeight) {stack.pollLast();}int width;if (stack.isEmpty()) width = len;else width = len - stack.peekLast() - 1;res = Math.max(res, curHeight * width);}return res;}
}


解法三:单调栈+哨兵

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);// 哨兵2号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;}
}


解法四:动态规划

class Solution {public int largestRectangleArea(int[] heights) {return maxArea(heights, 0, heights.length - 1);}public int maxArea(int[] heights, int left, int right) {if (left > right){return 0;}if (left == right){return heights[left];}int minIndex = left;int minHeight = heights[left];// 判断是否单调递增,且记录最小高度boolean ordered = true;for (int i = left + 1; i <= right; i++) {if (ordered) {if (heights[i] >= heights[i - 1]) {continue;} else {ordered = false;}}if (heights[i] < minHeight) {minIndex = i;minHeight = heights[i];}}// 单调递增,则可以直接计算当前能够计算的最大面积if (ordered) {int width = right - left + 1;int maxArea = 0;for (int i = left; i <= right; i++) {maxArea = Math.max(maxArea, width * heights[i]);width--;}return maxArea;}// 无序,三个中求最大:最大宽度*最小高度;最矮柱左边能形成的最大面积;最矮柱右边能形成的最大面积return Math.max(minHeight * (right - left + 1), Math.max(maxArea(heights, left, minIndex - 1),maxArea(heights, minIndex + 1, right)));}
}

leetcode84- 柱状图中最大的矩形(三种思路:暴力,单调栈+哨兵(详解),分治)相关推荐

  1. LeetCode--84.柱状图中最大的矩形(暴力法,单调栈)

    柱状图中最大的矩形(暴力法,单调栈) 1. 题目描述 2. 题目分析 3. C语言实现 3.1 暴力法 3.2 单调栈 4. Java实现 1. 题目描述 难度:困难 2. 题目分析 这道题有两种解法 ...

  2. Spring Boot项目(Maven\Gradle)三种启动方式及后台运行详解

    Spring Boot项目三种启动方式及后台运行详解 1 Spring Boot项目三种启动方法 运行Application.java类中的Main方法 项目管理工具启动 Maven项目:mvn sp ...

  3. java c3p0 配置文件_【c3p0】 C3P0的三种配置方式以及基本配置项详解

    数据库连接池C3P0框架是个非常优异的开源jar,高性能的管理着数据源,这里只讨论程序本身负责数据源,不讨论容器管理. ---------------------------------------- ...

  4. html5边框顶格,CSS 三种定位方式以及格式化上下文详解 》 html5jscss

    常规流( Normal flow ) 之称之为常规流,是因为这是相对于后面的浮动和绝对定位的一个概念,浮动和绝对定位元素都脱离了当前的常规流. 在 CSS2.1中,常规流包括块框( block box ...

  5. C3P0的三种配置方式以及基本配置项详解

    数据库连接池C3P0框架是个非常优异的开源jar,高性能的管理着数据源,这里只讨论程序本身负责数据源,不讨论容器管理. 注:需要的jar包在后面给出链接. ---------------------- ...

  6. 三种js轮播实现方式详解(看一遍就会)

    js轮播的三种实现方式 1.替换scr(入门级) <!DOCTYPE html> <html><head><meta charset="utf-8& ...

  7. 三种Cross-lingual模型 (XLM, XLM-R, mBART)详解

    本文将详述三种Cross-lingual模型,按照其在Arxiv上发表论文的时间,分别是XLM(2019/1/22).XLM-R(2019/11/5).mBART(2020/1/22),有意思的是这三 ...

  8. 二叉树的创建与三种遍历方式(带图文详解)

    二叉树是由多节点组成的,每个节点最多链接两个节点,这两个节点就称为根节点的左树和右树. 每个节点的由数据区,左树,右树组成. typedef struct node {int data;struct ...

  9. 三种CDN调度系统实现原理详解

    1. 调度系统是什么? 调度系统是指CDN厂家有能力通过各种机制将客户域名的所有现网请求引导到合适的目标机房,从而实现流量控制.质量控制.成本控制以及故障处理. 2. 接入CDN的方式 在讲解调度原理 ...

  10. 【BIM入门实战】Revit 图元分类有哪三种?Revit图元分类图文详解

    Revit在项目中使用3种类型的图元:模型图元.基准图元和视图专有图元. Revit中的图元也称为族.族包含图元的几何定义和图元所使用的参数.图元的每个实例都由族定义和控制. 1. 模型图元 模型图元 ...

最新文章

  1. MySQL 中的共享表空间与独立表空间如何选择
  2. Linux性能相关工具
  3. Python 爬虫进阶六之多进程的用法
  4. jQuery中绑定事件的几种方法
  5. Arch Linux 安装 Virtualbox 4.2.0 备忘录
  6. Linux添加keytool环境变量,linux keytool命令
  7. java中 @ExcelField 的使用
  8. magisk卸载内置软件_Win10自带软件怎么卸载 Win10自带软件卸载方法【详细教程】...
  9. 区块链技术及应用概述
  10. Cesium场景泛光
  11. 五种永久免费 内网穿透傻瓜式使用
  12. One-Stage Visual Grounding via Semantic-Aware Feature Filter
  13. 数据结构:大学的数据统计
  14. 一个案例两种分析方法告诉你数据涨跌异动该如何处理?附送涨跌问题常见五种假设
  15. Java单例模式详解--七种单例模式实现+单例安全+实际应用场景
  16. CSU 1596: Dick.Z 的炉石赛(模拟)
  17. ORA-01558故障恢复----惜分飞
  18. win7怎么打开html 文件夹,win7系统怎么设置一个窗口打开多个文件夹
  19. 人民银行备案企业AAA信用评级7证包含哪些?
  20. 第六课 511遇见易语言大漠找字FindStrFastEx打多怪实例

热门文章

  1. vue2.x源码解析(一)
  2. 前端晋升ppt_【PPT】快手前端架构师分享:前端发展史
  3. 变分自编码器 (Variational Autoencoders, VAEs)
  4. SAP License:ERP管理系统维护
  5. 版权保护利用区块链是否可以体现优势?
  6. 自己写的小型静态服务器
  7. 测试开发真的不难(5)如何让IDEA实时显示内存
  8. 申请美国计算机科学硕士,如何转专业申请美国计算机科学硕士?
  9. pycharm创建python工程_使用Pycharm(Python工具)新建项目及创建Python文件的教程
  10. LINUX设备驱动程序第三版.pdf,linux设备驱动程序第3版.pdf免费下载链接,学习资源下载