Day 63:单调栈 LeedCode 84.柱状图中最大的矩形

84. 柱状图中最大的矩形

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

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

示例 1:

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

示例 2:

输入: heights = [2,4]
输出: 4

提示:

  • 1 <= heights.length <=105
  • 0 <= heights[i] <= 104

思路:

本题和接雨水有相似之处

Day62:单调栈 LeedCode503. 下一个更大元素 II 42. 接雨水-CSDN博客

1.暴力法:

最大面积的矩形的高,一定是某个柱子的高

求出以每根柱子的高为矩形的高的矩形的最大矩形面积

寻找当前柱子的左边和右边第一个小于其高度的柱子,这两个柱子之间的宽度为矩形的宽w,h为当前柱子的高,面积为w*h

代码参考:

class Solution {public int largestRectangleArea(int[] heights) {int sum=0;for(int i=0;i<heights.length;i++){int left=i;int right=i;for(;left>=0;left--){if(heights[left]<heights[i]){break;}}for(;right<heights.length;right++){if(heights[right]<heights[i]){break;}}sum=Math.max(sum,(right-left-1)*heights[i]);}return sum;}
}

暴力法时间超过限制

2.双指针法:

为了得到两边的比当前高度矮的柱子,使用了暴力法,每到一个柱子都向两边遍历一遍,这其实是有重复计算的。我们把每一个位置的左边第一个高度小于当前高度的位置记录在一个数组上( minLeftIndex),右边第一个高度小于当前高度的位置记录在一个数组上(minRightIndex),这样就避免了重复计算。利用空间换时间

class Solution {public int largestRectangleArea(int[] heights) {int length = heights.length;int[] minLeftIndex = new int [length];int[] minRightIndex = new int [length];// 记录左边第一个小于该柱子的下标minLeftIndex[0] = -1 ;for (int i = 1; i < length; i++) {int t = i - 1;// 这里不是用if,而是不断向右寻找的过程while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];minLeftIndex[i] = t;}// 记录每个柱子右边第一个小于该柱子的下标minRightIndex[length - 1] = length;for (int i = length - 2; i >= 0; i--) {int t = i + 1;while(t < length && heights[t] >= heights[i]) t = minRightIndex[t];minRightIndex[i] = t;}// 求和int result = 0;for (int i = 0; i < length; i++) {int sum = heights[i] * (minRightIndex[i] - minLeftIndex[i] - 1);result = Math.max(sum, result);}return result;}
}

3.单调栈法

那么因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序!

为什么末尾和开头要加0?

首先来说末尾为什么要加元素0?

如果数组本身就是升序的,例如[2,4,6,8],那么入栈之后 从栈头到栈底都是单调递减,一直都没有走 情况一 计算结果的哪一步,所以最后输出的就是0了

开头为什么要加元素0?

如果栈中只有一个元素,将栈顶弹出得到mid,栈里没有元素了,那么为了避免空栈取值,直接跳过了计算结果的逻辑。

 所以我们需要在 height数组前后各加一个元素0。

  • 情况一:当前遍历的元素heights[i]小于栈顶元素heights[st.top()]的情况
  • 将栈中比当前元素小的都出栈

  • 情况二:当前遍历的元素heights[i]大于栈顶元素heights[st.top()]的情况
  • 直接入栈

  • 情况三:当前遍历的元素heights[i]等于栈顶元素heights[st.top()]的情况
  • 将栈顶的元素更新为当前元素

                                                         图略

代码参考:

class Solution {public int largestRectangleArea(int[] heights) {int result=0;LinkedList<Integer> list=new LinkedList<>();//首尾插入0int[] newHeigths=new int[heights.length+2];System.arraycopy(heights, 0, newHeigths, 1, heights.length);newHeigths[heights.length+1]=0;list.add(0);for(int i=1;i<newHeigths.length;i++){if(newHeigths[i]>newHeigths[list.get(list.size()-1)]){list.add(i);}else if(newHeigths[i]==newHeigths[list.get(list.size()-1)]){//可以省略list.remove(list.size()-1);list.add(i);}else{while(newHeigths[i]<newHeigths[list.get(list.size()-1)]){int mid=list.get(list.size()-1);list.remove(list.size()-1);int left=list.get(list.size()-1);int right=i;int w=right-left-1;int h=newHeigths[mid];result=Math.max(result,w*h);}list.add(i);}}return result;}
}

public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

src:源数组;

srcPos:源数组要复制的起始位置;

dest:目的数组;

destPos:目的数组放置的起始位置;

length:复制的长度.

总结:

要解决本题就要快速找到当前位置的左边第一个高度低于当前值的位置和右边第一个高度低于当前值的位置

为什么单调栈能帮我们快速找出这两个位置?

对于栈顶元素,栈顶往栈底方向的下一个元素,是第一个小于当前值的(从栈低到栈顶递增),所以对于单调栈很容易找到左边那个位置,如果接下来即将入栈的元素小于栈顶对应的值,那这个接下来要入栈的元素不就是我们要找的那个右边的那个值吗?

建议与接雨水题目一起思考:

Day62:单调栈 LeedCode503. 下一个更大元素 II 42. 接雨水-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/675039.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CMakeLists.txt语法规则:foreach 循环基本用法

一. 简介 cmake 中除了 if 条件判断之外&#xff0c;还支持循环语句&#xff0c;包括 foreach()循环、while()循环。 本文学习 CMakeLists.txt语法中的循环语句。 CMakeLists.txt语法中 有两种 循环实现方式&#xff1a;foreach循环与 while循环。 二. CMakeLists.txt语法规则…

黑马点评项目总结

登录 基于session登录 短信验证码登录 配置登录拦截器 向 Spring MVC 框架中添加拦截器&#xff0c;LoginInterceptor 是一个自定义的拦截器&#xff0c;用于拦截用户的登录请求。 excludePathPatterns这一句是设置拦截器需要放行的请求路径列表。 "/user/code", …

图片编辑工具-Gimp

一、前言 GIMP&#xff08;GNU Image Manipulation Program&#xff09;是一款免费开源的图像编辑软件&#xff0c;具有功能强大和跨平台的特性。 GIMP作为一个图像编辑器&#xff0c;它提供了广泛的图像处理功能&#xff0c;包括但不限于照片修饰、图像合成以及创建艺术作品…

渗透测试流程

一、攻击流程 信息收集阶段→漏洞分析阶段→攻击阶段→后渗透阶段 二、信息收集 1、收集内容&#xff1a; IP资源&#xff1a;真实IP获取、旁站信息收集、C段主机信息收集域名发现&#xff1a;子域名信息收集、子域名枚举发现子域名、搜索引擎发现子域名、第三方聚合服务器发…

实战Java虚拟机-基础篇

一、基础篇-Java内存区域 1.运行时数据区 运行时数据区-总览 Java虚拟机在运行Java程序过程中管理的内存区域&#xff0c;称之为运行时数据区。 《Java虚拟机规范》中规定了每一部分的作用。 1.程序计数器 程序计数器&#xff08;Program Counter Register&#xff09;也叫…

【嵌入式必读】一文彻底理解PID自整定及PID自整定代码设计

文章目录 1. 前言2. PID简介3. 常用的PID自整定方法3.1 临界度比例法3.2 衰减曲线法 4. 继电反馈整定法原理4.1 继电反馈自整定的基本思想4.2 继电反馈自整定原理 5. 算法设计5.1 振荡的生成5.2 提取出临界周期 T c T_c Tc​和振荡波形幅值 A A A5.3 计算出PID参数 6 原代码6.1…

浅谈操作系统中的重要概念——线程(3)——设计模式

文章目录 一、什么是设计模式&#xff1f;二、单例模式2.1、饿汉模式2.2、懒汉模式2.3、多线程情况下调用 饿汉模式与懒汉模式 谁是安全的&#xff1f;&#xff1f;&#xff08;重点&#xff09; 三、工厂模式 一、什么是设计模式&#xff1f; 设计模式就相当于菜谱&#xff0…

【idea-sprongboot项目】SSH连接云服务器进行远程开发

继上一篇博客【阿里云服务器】ubuntu 22.04.1安装docker以及部署java环境-CSDN博客 目录 五、远程开发方式 1&#xff09;SSH进行远程开发 步骤 配置文件同步 window电脑远程操控 正式通过window电脑远程操控 运行在linux服务器上的远程程序 调试在linux服务器上的远程程…

PXE批量安装

系统装机的三种引导方式 u盘光盘网络装机 光盘&#xff1a; 1.类似于usb模式 2.刻录模式 系统安装过程 加载boot loader Boot Loader 是在操作系统内核运行之前运行的一段小程序。通过这段小程序&#xff0c;我们可以初始化硬件设备、建立内存空间的映射图&#xff0c;从…

Partisia Blockchain 生态首个zk跨链DEX现已上线

在5月1日&#xff0c;由Partisia Blockchain与zkCross创建合作推出的Partisia zkCrossDEX在Partisia Blockchain生态正式上线。Partisia zkCrossDEX是Partisia Blockchain上重要的互操作枢纽&#xff0c;其融合了zkCross的zk技术跨链互操作方案&#xff0c;并利用Partisia Bloc…

Prompt提示词教程 | 提示工程指南 | 提示词示例 入门篇

在上一节中&#xff0c;我们介绍并给出了如何赋能大语言模型的基本示例。如果还没看而且是刚入门的同学建议看下&#xff0c;有个基本概念。 Prompt提示词教程 | 提示工程指南 | 提示工程简介https://blog.csdn.net/HRG520JN/article/details/138523705在本节中&#xff0c;我…

一堆自定义C#代码片段,让你开发效率飞涨

SharpBoxes 是一款用于 Visual Studio 的扩展&#xff0c;作者为本人&#xff1b; 该扩展旨在提高开发效率。它为开发人员提供了一组日常使用频率较高的代码片段&#xff0c;让你在编写代码时能够更快地插入常用的代码段。通过安装这个扩展&#xff0c;你可以使用快捷键轻松插…