Largest Rectangle in Histogram

原题链接Largest Rectangle in Histogram

给定一个直方图,计算这个直方图中最大的矩形面积。输入的是直方图中每个柱的高度

首先可以想到要求面积就需要确定矩形的高度,但是每个柱子的高度是不一样的,而不同的柱子组成的矩形要以最短的那个作为高

那么,是否可以对每个高度的分别计算面积呢?简单的说就是以每个柱子的高度作为最后矩形的高度,计算形成的最大矩形的面积

隐含的方法就是对于每个柱子,它的高度记为H,需要

  • 向左找第一个高度小于H的柱子位置,下标记为l
  • 向右找第一个高度小于H的柱子位置,下标记为r

那么,以H作为高的矩形的宽为(r - l - 1),面积为(r - l - 1) * H

只需要把所有这样的面积求出来取最大值即可

代码如下

class Solution {
public:int largestRectangleArea(vector<int>& heights) {int maxArea = 0;for(int i = 0; i < heights.size(); ++i){/* 向左找第一个小于当前高度的位置 */int l = i - 1;while(l >= 0 && heights[l] >= heights[i])--l;/* 向右找第一个小于当前高度的位置 */int r = i + 1;while(r < heights.size() && heights[r] >= heights[i])++r;/* 计算面积 */maxArea = std::max(maxArea, (r - l - 1) * heights[i]);}return maxArea;}
};

但是,这种方法超时了:(
可以想到时间主要都消耗在内部的两个while循环,其实循环目的没错,为了寻找矩形的左右边界,但是试想,如果heights中所有元素都相等(极端情况),那么每次while循环可能都需要遍历整个heights直到l < 0或者r >= heights.size()

可以从这两方面入手,考虑如何优化两个while循环


先考虑寻找左边界时的优化

假设需要找heights[i]的左边界,根据上述方法,需要一次遍历

i-1, i-2, ..., k1

找到第一个k1满足

heights[k1] < heights[i]

在下次循环中(i = i + 1),又需要找heights[i+1]的左边界,同样的遍历方法

i, i-1, i-2, ..., k2

找到第一个k2满足

heights[k2] < heights[i+1]

仔细观察这两次循环,实际上是存在重复部分的,在找heights[i+1]的左边界过程中,假设有

heights[i] >= heights[i+1]

那么下次其实不需要从i-1开始继续比较heights[i-1] >= heights[i+1],因为当遍历i+1时,有些东西是已知的,那就是

  • 第一个小于heights[i]的位置,即k1

由于heights[i] >= heights[i+1],从i, i-1, …, k+1这些位置上的元素一定也都大于等于heights[i+1],那么为什么不从k1开始比较呢,是吧:)

当然这种方法是建立在对heights的遍历是从左向右的,即

for(int i = 0; i < heights.size(); ++i)...//寻找heights[i]的左边界

对于右边界,就需要让heights的遍历从右向左

for(int i = heights.size() - 1; i >= 0; --i)...//寻找heights[i]的右边界

最后再来一次循环,但是这次heights[i]的左边界和右边界都是已知的

class Solution {
public:int largestRectangleArea(vector<int>& heights) {if(heights.empty())return 0;int n = heights.size();vector<int> L(n, 0);vector<int> R(n, 0);for(int i = 0; i < n; ++i){int l = i - 1;while(l >= 0 && heights[l] >= heights[i])l = L[l];   //直接从k1开始找L[i] = l;}for(int i = n - 1; i >= 0; --i){int r = i + 1;while(r < n && heights[r] >= heights[i])r = R[r];   //直接从k1开始找R[i] = r;}int maxArea = 0;for(int i = 0; i < n; ++i){//L[i]表示左边第一个小于heights[i]的位置//R[i]表示右边第一个小于heights[i]的位置maxArea = std::max(maxArea, (R[i] - L[i] - 1) * heights[i]);}return maxArea;}
};

当然啦,如果觉得for循环有点多,可以把后两个合在一起:)

class Solution {
public:int largestRectangleArea(vector<int>& heights) {if(heights.empty())return 0;int n = heights.size();vector<int> L(n, 0);vector<int> R(n, 0);for(int i = 0; i < n; ++i){int l = i - 1;while(l >= 0 && heights[l] >= heights[i])l = L[l];   //直接从k1开始找L[i] = l;}int maxArea = 0;for(int i = n - 1; i >= 0; --i){int r = i + 1;while(r < n && heights[r] >= heights[i])r = R[r];   //直接从k1开始找R[i] = r;maxArea = std::max(maxArea, (R[i] - L[i] - 1) * heights[i]);}return maxArea;}
};

其实通常首先想到的就是最开始那个一个for循环,内部两个while找左右边界的版本,但是实际上while循环是可以优化的,如果知道优化的方法(找到重复计算的原因),效率会高很多

每天一道LeetCode-----计算直方图中最大矩形的面积相关推荐

  1. 直方图中最大矩形面积

    原文地址:http://www.geeksforgeeks.org/largest-rectangle-under-histogram/ 注意:本文并未对原文完整翻译,而是结合原文并根据本人理解写出, ...

  2. c语言直方图最大矩形面积,直方图中最大矩形面积(示例代码)

    注意:本文并未对原文完整翻译,而是结合原文并根据本人理解写出,因此部分内容为完整翻译,部分内容为个人理解所写. Largest Rectangle in Histogram 直方图中最大矩形面积 一个 ...

  3. c语言直方图最大矩形面积,利用枚举法求直方图中最大矩形面积的方法实例

    求直方图中的最大矩形面积: 例如给定直方图{2,3,1,2,4,2} 则直方图中最大矩形面积为x=(3,6),|x|=3,y=2,max面积=6 思考:利用枚举法 /*当前位置往前进行枚举法*/ pu ...

  4. 计算直方图中面积最大的矩形

    CSDN编程挑战里的题目 给定直方图,每一小块的height由N个非负整数所确定,每一小块的width都为1,请找 出直方图中面积最大的矩形. 如下图所示,直方图中每一块的宽度都是1,每一块给定的高度 ...

  5. 每日一道Leetcode -网格矩阵中的路径相关系列【动态规划|路径中(不)含值|有无障碍物|最小路径和】

    class Solution:def uniquePaths(self, m: int, n: int) -> int:"""排列组合方法:从左上角到右下角的过程中 ...

  6. 直方图中最大的矩形(单调栈2)

    题目描述 直方图是由在公共基线处对齐的一系列矩形组成的多边形. 矩形具有相等的宽度,但可以具有不同的高度. 例如,图例左侧显示了由高度为2,1,4,5,1,3,3的矩形组成的直方图,矩形的宽度都为1: ...

  7. java计算矩形的面积和周长的方法

    在生活中,我们常常需要计算某个矩形的面积和周长,如我们经常用的计算器就是个不错的选择,它可以计算出任意一个矩形的面积和周长.那么,如果你想使用 Java编程语言来计算矩形的面积和周长,你该如何做呢?今 ...

  8. 庞果网之寻找直方图中面积最大的矩形

    题目详情 给定直方图,每一小块的height由N个非负整数所确定,每一小块的width都为1,请找出直方图中面积最大的矩形. 如下图所示,直方图中每一块的宽度都是1,每一块给定的高度分别是[2,1,5 ...

  9. 去掉数组最后一个元素_leetcode 34. 在排序数组中查找元素的第一个和最后一个位置每天刷一道leetcode算法系列!...

    作者:reed,一个热爱技术的斜杠青年,程序员面试联合创始人 前文回顾: leetcode1. 两数之和--每天刷一道leetcode系列! leetcode2. 两数相加--每天刷一道leetcod ...

最新文章

  1. 详解微信域名防封的方法以及检测等工具的技术原理
  2. 「golang」panic: commands out of sync. Did you run multiple statements at once
  3. Java 复制一个文件到另外一个目录下
  4. 在代码中获取ApplicationContext实例
  5. Centos7.5.1804永久生效修改主机名
  6. 组合CPU和DRAM
  7. 类从未使用_如果您从未依赖在线销售,如何优化您的网站
  8. 聊聊面试的事(应聘方)
  9. 去掉左边0_SLAM从0到1——11. 视觉里程计VO内容框架
  10. 【剑指offer - C++/Java】14、链表中倒数第k的节点
  11. angularjs 结构的两种写法(2)
  12. ff14 服务器位置,ff14转服在哪里
  13. 怎么在线批量网站打开?
  14. 字体转换,woff,ttf,otf,eot,svg
  15. opnet中SOCKET接口开发
  16. 导航网站完整程序源码
  17. 2022年京东新百货七夕礼遇季活动有什么亮点?
  18. Linux 虚拟内存
  19. python 表格处理项目该如何分工_python 处理 Excel 表格
  20. Felix入门与实践(一)

热门文章

  1. Java黑皮书课后题第8章:*8.26(行排序)用下面的方法实现一个二维数组中的行排序。返回新数组,且原数组保持不变。编写一个测试程序,提示用户输入一个3*3的double型矩阵,显示一个排好的矩阵
  2. oracle jdbctype null,Oracle数据库之springboot 项目mybatis plus 设置 jdbcTypeForNull
  3. POJ 2083 递归画分形图
  4. WTL 自绘 进度条Progressbar
  5. Sharepoint client model 中出现Cannot invoke HTTP DAV request. There is a pending query 的解决办法...
  6. FK JavaScript之:ArcGIS JavaScript API之地图动画
  7. using可以用于释放操作,相当于Dispose()
  8. js获取最近几天的日期(转载)
  9. Android-----Resources
  10. PowerDesigner 反向工程生成ER图