一、前言

问题来源LeetCode 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

三、思路

三种解法

3.1 方法一:暴力解法

  1. 从左往右遍历,每一个矩形
  2. 对于当前遍历的矩形,它包含它在内的最大矩形是,向右和向左分别找到第一个高度小于它的矩形,它们围起来的矩形即为最大矩形。
  3. 找到遍历中最大的矩形即为所求

上图输入为 : [5,7,8,10,4,4,5,7]

坐标0:高度5, 左边没有大于或等于的矩形,右边到坐标3,面积:20 = 5*4

坐标1:高度7, 左边没有大于或等于的矩形,右边到坐标3,面积:21 = 7*3

坐标2:高度8, 左边没有大于或等于的矩形,右边到坐标3,面积:16 = 8*2

坐标3:高度10,左边没有大于或等于的矩形,右边没有, 面积:10 = 10*1

坐标4:高度4, 左边到坐标1,右边到坐标7,面积:32 = 4*8

坐标5:高度4, 和上一个坐标5高度相等,最大面积也相等,不用计算

坐标6:高度5, 左边没有,右边到坐标7,面积:10 = 5*2

坐标7:高度7, 左边没有,右边没有,面积:7 = 7*1

最大面积为:32

复杂度分析

  • 时间复杂度:O(n2)。
  • 空间复杂度:O(1) 。不需要额外的空间。

3.2 方法二:分治法

通过观察,可以发现,最大面积矩形存在于以下几种情况:

  1. 确定了最矮柱子以后,矩形的宽尽可能往两边延伸。
  2. 在最矮柱子左边的最大面积矩形(子问题)。
  3. 在最矮柱子右边的最大面积矩形(子问题)。

上图输入为 : [5,7,8,10,4,4,5,7]

1.当前第一个最小高度为4(坐标4),最小高度最大矩形面积为 32 = 4*8。

2.矩形左边(坐标0-3)最大面积:15。

3.矩形右边(坐标6-7)最大面积:10。(备注:坐标5和坐标4相邻且高度相等,最大面积已经计算)

复杂度分析

  • 时间复杂度:O(nlogn)。
  • 空间复杂度:O(n) 。不需要额外的空间。

3.3 方法三:栈

方法一中是按照给定的矩形,向左右两边寻找至下一个小于它的高度。继续观察这个图发现当f(n) < f(n-1) 的时候,f(n)不再需要向右查找,只需要向左查找。那需要向左查找到什么时候为止呢?只需要保证左边为升序即可。以上图为例。

1. f(0) < f(1) < f(2) < f(3) , f(4) 不大于f(3),往前寻找到小于f(4)为止,也就是当我们遍历到f(4) 时,已经可以确定 f(3)所包含的最大矩形面积:10 = 10*1

2. 接着往前寻找,f(2) > f(4),f(2)包含的最大矩形面积可以确定:16 = 8*2

3. 接着往前寻找,f(1) > f(4),f(1)包含的最大矩形面积可以确定:21 = 7*3

4. 接着往前寻找,f(0) > f(4),f(0)包含的最大矩形面积可以确定:20 = 5*4

5. f(4) 是当前最小的高度,往前查找,f(5) 等于 f(4),坐标5包含的最大矩形和坐标4包含的最大矩形,不用重复计算

6. f(6) > f(4),f(7) > f(6) 继续往后搜索,已经到头了(可以在最后面添加高度为0的矩形)。往前搜索,

同理f(7)包含的最大矩形面积可以确定:7 = 7*1

f(6)包含的最大矩形面积可以确定:10 = 5*2

7. 现在只剩下 f(4),剩下的最后一个即为高度最低的一个面积为 f(4) = 4*8

总结:

分析完我们发现,从左往右遍历,当f(n) > f(n-1)需要放入队列里面;当f(n) <= f(n-1)的时候,f(n-1)最大面积可以确认,f(n-1)离开队列,继续判断队列首元素,直至小于f(n)为止。我们可以用栈维持这个队列。栈中元素为坐标值。

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(n) 。需要维持一个栈。

五、编码实现

//==========================================================================
/**
* @file : 84_LargestRectangleArea.h
* @title: 柱状图中最大的矩形
* @purpose : 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1。求在该柱状图中,能够勾勒出来的矩形的最大面积。
*
* 示例:
*
* 输入:
* 输入: [2,1,5,6,2,3]
* 输出: 10
*
* 来源:力扣(LeetCode)
* 难度:困难
* 链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
*
*/
//==========================================================================
#pragma once#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>using namespace std;#define NAMESPACE_LARGESTRECTANGLEAREA namespace NAME_LARGESTRECTANGLEAREA {
#define NAMESPACE_LARGESTRECTANGLEAREAEND }
NAMESPACE_LARGESTRECTANGLEAREA// 解法一:暴力解决
// 复杂度分析
// 时间复杂度:O(n2)。
// 空间复杂度:O(1) 。不需要额外的空间。
//
// 执行用时 : 1836 ms, 在所有 C++ 提交中击败了 5.00 % 的用户
// 内存消耗 : 7.5 MB, 在所有 C++ 提交中击败了 100.00 % 的用户
class Solution_1
{
public:int largestRectangleArea(vector<int>& heights){int maxArea = 0;for (int i = 0; i < heights.size(); ++i){if (i > 0 && heights[i] == heights[i - 1]){// 如果和前面相等之前已经计算过continue;  }int wide = 1;// 向前搜索for (int j = i + 1; j < heights.size() && heights[j] >= heights[i]; ++j, ++wide);// 向后搜索for (int j = i - 1; j >= 0 && heights[j] >= heights[i]; --j, ++wide);maxArea = max(heights[i] * wide, maxArea);}return maxArea;}
};// 解法二:分治法
// 复杂度分析
// 时间复杂度:O(nlogn)。
//空间复杂度:O(n) 。不需要额外的空间。
//
// 执行用时: 632 ms, 在所有 C++ 提交中击败了 8.53 %的用户
// 内存消耗 : 14 MB, 在所有 C++ 提交中击败了 9.52 % 的用户
class Solution_2
{
public:int largestRectangleArea(vector<int>& heights) {if (heights.empty()){return 0;}return largestRectangleArea(heights, 0, heights.size() - 1);}private:int largestRectangleArea(vector<int>& heights, int left, int right){if (left < 0 || right > heights.size()-1 || left > right){return 0;}if (left == right){return heights[left];}int minIndex = left;int minHeights = heights[left];for (int i = left; i <= right; ++i){if (heights[i] < minHeights ){// 找第一个最小值minHeights = heights[i];minIndex = i;}}// 最小高度,矩形面积int minHeightArea = (right - left + 1) * minHeights;// 搜索左边最大矩形面积int maxLeft = minIndex - 1;int maxAreaLeft = largestRectangleArea(heights, left, maxLeft);// 搜索右边最大矩形面积int minRight = minIndex + 1;for (int i = minIndex + 1; i <= right && heights[i] == heights[minIndex]; ++i, ++minRight);int maxAreaRight = largestRectangleArea(heights, minRight, right);return max(minHeightArea, max(maxAreaLeft, maxAreaRight));}
};// 解法3:栈
// 复杂度分析
// 时间复杂度:O(n)。
// 空间复杂度:O(n) 。需要维持一个栈。
//
// 执行用时: 16 ms, 在所有 C++ 提交中击败了 75.31%的用户
// 内存消耗 : 8.5 MB, 在所有 C++ 提交中击败了 100 % 的用户
class Solution_3
{
public:int largestRectangleArea(vector<int>& heights) {stack<int> st;heights.push_back(0);//结尾虚拟柱子高度0int size = heights.size();int res = 0;for (int i = 0; i < size; ++i) {while (!st.empty() && heights[st.top()] >= heights[i]) {int val = st.top();st.pop();res = max(res, heights[val] * (st.empty() ? i : (i - st.top() - 1)));//宽度不包含当前元素}st.push(i);}return res;}
};以下为测试代码//
// 测试 用例 START
void test(const char* testName, vector<int>& heights, int expect)
{Solution_1 s1;Solution_2 s2;Solution_3 s3;int result1 = s1.largestRectangleArea(heights);int result2 = s2.largestRectangleArea(heights);int result3 = s3.largestRectangleArea(heights);if (expect == result1 && expect == result2 && expect == result3){cout << testName << ", solution passed." << endl;}else{cout << testName << ", solution failed. result1: " << result1 << ",result2: " << result2 << ",result3: " << result3 << endl;}
}void Test1()
{vector<int> heights;int expect = 0;test("Test1()", heights, expect);
}void Test2()
{vector<int> heights = { 1 };int expect = 1;test("Test2()", heights, expect);
}void Test3()
{vector<int> heights = { 0, 9 };int expect = 9;test("Test3()", heights, expect);
}void Test4()
{vector<int> heights = { 9, 0 };int expect = 9;test("Test4()", heights, expect);
}void Test5()
{vector<int> heights = { 1, 2, 3, 4, 5 };int expect = 9;test("Test5()", heights, expect);
}void Test6()
{vector<int> heights = { 5, 4, 3, 2, 1 };int expect = 9;test("Test6()", heights, expect);
}void Test7()
{vector<int> heights = { 1, 2, 3, 4, 5, 4, 3, 2, 1 };int expect = 15;test("Test7()", heights, expect);
}void Test8()
{vector<int> heights = { 2, 1, 5, 6, 2, 3 };int expect = 10;test("Test8()", heights, expect);
}NAMESPACE_LARGESTRECTANGLEAREAEND
// 测试 用例 END
//void LargestRectangleArea_Test()
{NAME_LARGESTRECTANGLEAREA::Test1();NAME_LARGESTRECTANGLEAREA::Test2();NAME_LARGESTRECTANGLEAREA::Test3();NAME_LARGESTRECTANGLEAREA::Test4();NAME_LARGESTRECTANGLEAREA::Test5();NAME_LARGESTRECTANGLEAREA::Test6();NAME_LARGESTRECTANGLEAREA::Test7();
}

执行结果:

柱状图中最大的矩形多种解法相关推荐

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

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

  2. 单调栈:leetcode 84. 柱状图中最大的矩形/85最大矩形

    84. 柱状图中最大的矩形 遍历数组,以每一个元素作为高,向左右两边拓展,遇到第一个比该元素小的位置停下 图片源自leetcode力扣 一.暴力解法(超时) 遍历数组,以每一个元素作为高,向左右两边拓 ...

  3. c语言力扣l最大矩形,leetcode 84柱状图中最大的矩形,利用单调栈求解l

    利用单调了栈求解leetcode 84柱状图中最大的矩形 image image 利用单调递增栈的方式来实现,计算发生在每次弹出栈顶的操作过程中 单调递增栈的操作步骤 1.如果栈为空或者栈顶元素比入栈 ...

  4. 算法:多数元素,多种解法

    前言: 以前做数学题的时候,老师说:你们学习多种解题方法.遇到类似不同的问题,你都会了,这样能提高解题能力.如果你写出多种解法,面试官会对你刮目相看. 下面一题,我们将用多种解法实现,是面试中常见的一 ...

  5. Minimum Inversion Number HDU - 1394(求一个数字环的逆序对+多种解法)

    题意: 给出n个数(0~n-1,每个数仅出现一次),问它长为n的循环序列中逆序对最少的数量. 多种解法:暴力+树状数组+分治+规律推导公式 题目: The inversion number of a ...

  6. java 柱状图 宽度_Java实现 LeetCode 84 柱状图中最大得矩形

    84. 柱状图中最大的矩形 给定 n 个非负整数,用来表示柱状图中各个柱子的高度.每个柱子彼此相邻,且宽度为 1 . 求在该柱状图中,能够勾勒出来的矩形的最大面积. 以上是柱状图的示例,其中每个柱子的 ...

  7. 在柱状图中找最大矩形——O(n)时间复杂度java实现

    在柱状图中找最大矩形--O(n)时间复杂度java实现 ZZ:http://blog.csdn.net/xybsos/article/details/8049048 具体题目如下:给一组非负的整数来表 ...

  8. 【LeetCode】【HOT】84. 柱状图中最大的矩形(栈)

    [LeetCode][HOT]84. 柱状图中最大的矩形 文章目录 [LeetCode][HOT]84. 柱状图中最大的矩形 package hot;import java.util.ArrayDeq ...

  9. 计算机求百钱买百鸡采用的算法,多种解法求百钱百鸡问题.doc

    多种解法求百钱百鸡问题 学 号: 0121210680225 <算法设计与分析B> 大 作 业 题 目多种解法求百钱百鸡问题学 院计算机科学与技术学院专 业软件工程班 级Sy1201姓 名 ...

最新文章

  1. 服务器唯一id生成规则
  2. 世界在音乐中得到了完整的再现和表达。
  3. 免费阿里云服务器超爽体验(为阿里做个广告吧)
  4. 2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)
  5. 如何用C#检查硬盘是否是固态硬盘SSD
  6. uC/OS-II源码分析(总体思路 三)
  7. 密封槽设计标准_哈尔滨轴承 | 超全面机械密封选型
  8. macOS下的视频格式转换器
  9. leetcode1306. 跳跃游戏 III(bfs)
  10. squid3.0缓存服务器编译安装
  11. Java常见加密方式
  12. 打造一款CPS返佣小程序之创建淘宝联盟账号及获取饿了么佣金路径《二》
  13. Android Alpha换算表
  14. ~ 关于中医给的建议~ 好好调理身体~
  15. 在Ubuntu上安装Tensorflow Serving
  16. Codeforces 1090C New Year Presents
  17. 【LTE学习日记01】子载波功率与信道功率的换算
  18. Logstash:使用 dissect 导入 CSV 格式文档
  19. vue老项目升级vue-cli3.0问题总结
  20. 王道操作系统课代表 - 考研计算机 第一章 计算机概述 究极精华总结笔记

热门文章

  1. 中序遍历二叉树非递归
  2. 7-5 华氏度转摄氏度(四舍五入) (5分) java
  3. h5公众号分享朋友、朋友圈
  4. Python max函数
  5. 怎样提取电影片段做gif?仅需三步在线截取gif动图
  6. 广东专升本C语言程序设计(完结)
  7. 错误模块名称: KERNELBASE.dll解决方案
  8. python爬取贝壳找房之北京二手房源信息
  9. iPad Pro机身无故弯曲 Apple对此做出回应及应对
  10. 2021上半年,计算机考研大学热搜排名!