从LeetCode:Largest Rectangular Area in a Histogram(直方图最大面积) 说开去
来源:互联网 发布:抓取网页数据 编辑:程序博客网 时间:2024/06/06 04:21
欢迎到我的博客www.vincentbel.com中进行查看。
这是LeetCode上的一道算法题,以下内容是我在解这道题的思路和这道题的一个应用。
题目
Largest Rectangular Area in a Histogram
Given n non-negative integers representing the histogram’s bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.
Above is a histogram where width of each bar is 1, given height =
[2,1,5,6,2,3]
.The largest rectangle is shown in the shaded area, which has area = 10 unit.
For example,
Given height =[2,1,5,6,2,3]
,
return 10.
简单的说就是:已知直方图每一根柱子的高度,求其能组成的长方形的最大面积。
思路
最大的矩形面积,其高度一定是其中的一根最低的柱子的高度,例如:
最低柱子:高度为5的柱子(第3根柱子)
最低柱子:高度为4的柱子(第4根柱子)
所以,最终的结果一定是
所以,问题就变成了:如何计算以第i
根柱子为最低柱子的最大矩形面积?
计算以第i
根柱子为最低柱子的最大矩形面积Si
记第i
根柱子的高度为 height[i]
;
计算以第i
根柱子为最低柱子的最大矩形面积Si
,高度已经知道,是height[i]
;还需要计算其底边长:
从第i
根柱子开始:
- 向左算出第一根高度小于height[i]
的柱子,记其下标为left_index
;
- 向右算出第一根高度小于height[i]
的柱子,记其下标为 right_index
。
则底边长 = (right_index - left_index - 1)
,所以: Si = height[i] * (right_index - left_index - 1)
。
例如:
对于第4根柱子(高度height[4] = 4
),向左第一根高度小于height[4]
的柱子是第2根柱子,其高度为2;向右第一根高度小于height[4]
的柱子是第6根柱子,其高度为1;所以S4 = 4 * (6 - 2 - 1) = 12
从左到右遍历所有柱子,遍历到第i
根柱子时,如果要计算Si
,其左边界容易确定,但右边界是第i
根柱子右边的柱子,无法确定,所以无法计算面积Si
。
换个思路,遍历到第i
根柱子时,所有以第i
根柱子为右边界的柱子j
(0 < j < i
)的右边界就确定了,所以Sj
就能够计算了。
哪些柱子会以第i
根柱子为右边界?肯定是高度大于height[i]
的柱子。
使用一个栈s
来存储无法确定右边界的柱子的下标,进行以下操作:
- 当栈为空时,将i
入栈:s.push(i)
,i++
- 当 height[i] >= 栈顶元素的高度
,将i
入栈:s.push(i)
, i++
- 当height[i] < 栈顶元素的高度
,说明 第i
根柱子 是当前栈顶元素(也就是第 s.top()
根柱子) 的右边界,所以可以计算其面积:
- right_index = i
- left_index =
当前栈顶下的第一个元素;只需执行以下操作:
- s.pop();
- left_index = s.top();
实现
具体代码如下:
int largestRectangleArea(vector<int> &height) { int n = height.size(); int i = 0; int max_area = 0; // 最大面积 stack<int> s; while (i < n) { if (s.empty() || height[i] >= height[s.top()]) { // 如果栈为空或者 height[i] >= 栈顶元素的高度,将 i 进栈 s.push(i); i++; } else { int current = s.top(); // 当前要计算面积的柱子的下标 s.pop(); // 左边界,如果栈为空,则以第一根柱子前一位为左边界 // 在这里第一根柱子下标为0,所以以 -1 为左边界 int left_index = s.empty() ? -1 : s.top(); int current_area = height[current] * (i - left_index - 1); // 右边界 == i if (current_area > max_area) { // 如果当前计算面积比之前计算的所有面积都大,则更新最大面积 max_area = current_area; } } } while (!s.empty()) { // 计算栈中剩余元素的面积 int current = s.top(); s.pop(); int left_index = s.empty() ? -1 : s.top(); int current_area = height[current] * (i - left_index - 1); if (current_area > max_area) { max_area = current_area; } } return max_area;}
简化代码
如果给最后加上一个元素元素 0 作为所有柱子的右边界,则在while (i < n)
循环结束后栈一定是空的,可以简化代码如下:
int largestRectangleArea(vector<int> &height) { height.push_back(0); // 最后加上一个元素 0 作为所有柱子的右边界 int n = height.size(); int i = 0; int max_area = 0; // 最大面积 stack<int> s; while (i < n) { if (s.empty() || height[i] >= height[s.top()]) { // 如果栈为空或者 height[i] >= 栈顶元素的高度,将 i 进栈 s.push(i); i++; } else { int current = s.top(); // 当前要计算面积的柱子的下标 s.pop(); int left_index = s.empty() ? -1 : s.top(); // 左边界 int current_area = height[current] * (i - left_index - 1); // 右边界 == i if (current_area > max_area) { // 如果当前计算面积比之前计算的所有面积都大,则更新最大面积 max_area = current_area; } } } return max_area;}
应用
LeetCode 上的另一题:Maximal Rectangle
Given a 2D binary matrix filled with 0’s and 1’s, find the largest rectangle containing all ones and return its area.
一开始看这个题目以为是要计算包含了所有1
的长方形的最大面积,那这样取最大的不就好了?显然题目不是这意思,题目的意思是长方形全部由1
组成,求这样的长方形的最大面积。
从上到下遍历每一行,对于第i
行,只要计算出每一列的高(相当于前面所说的每根柱子的高),就能按照之前的方法计算出最大面积。
计算出每一列的高
用i
表示当前行,用j
表示当前列,用height[i][j]
表示其高度
- 如果 matrix[i][j] == '0'
,则height[i][j] = 0
- 如果 matrix[i][j] == '1'
:
- 如果当前是第一行,则height[i][j] = 1
- 否则:height[i][j]
等于前一行当前列的高度加1, 也就是:
height[i][j] = height[i - 1][j] + 1
其实只需要用一维数组height[j]
表示高度,因为在计算height[j]
时,其值就等于前一行当前列的高度,也就是:height[j] = height[j] + 1
。对于第1行,只需将height[j]
全部初始化为 0 即可。
具体代码如下:
int maximalRectangle(vector<vector<char> > &matrix) { int numRows = matrix.size(); // 行数 if (numRows <= 0) { return 0; } int numColumns = matrix[0].size(); // 列数 int max_area = 0; int * height = new int[numColumns + 1]; memset(height, 0, numColumns * sizeof(int)); // 将height初始化为 0 height[numColumns] = -1; // 最后加上元素 -1 作为所有元素的右边界 for (int i = 0; i < numRows; ++i) { // 遍历每一行 for (int j = 0; j < numColumns; ++j) { height[j] = (matrix[i][j] == '1') ? height[j] + 1 : 0; } int j = 0; stack<int> s; while (j <= numColumns) { if (s.empty() || height[j] >= height[s.top()]) { // 如果栈为空或者 height[j] >= 栈顶元素的高度,将 j 进栈 s.push(j); j++; } else { int current = s.top(); // 当前要计算面积的柱子的下标 s.pop(); int left_index = s.empty() ? -1 : s.top(); // 左边界 int current_area = height[current] * (j - left_index - 1); // 右边界 == j if (current_area > max_area) { // 如果当前计算面积比之前计算的所有面积都大,则更新最大面积 max_area = current_area; } } } } delete[] height; return max_area;}
参考资料
[1] http://www.geeksforgeeks.org/largest-rectangle-under-histogram/
- 从LeetCode:Largest Rectangular Area in a Histogram(直方图最大面积) 说开去
- Largest Rectangular Area in a Histogram:leetcode
- leetcode-Largest Rectangular Area in a Histogram
- leetcode 84:Largest Rectangular Area in a Histogram
- Largest Rectangular Area in a Histogram
- LeetCode: Largest Rectangle in Histogram(直方图最大面积)
- Largest Rectangle in Histogram (直方图中最大面积) 【leetcode】
- 4.1.3LeetCode: Largest Rectangle in Histogram(直方图最大面积)
- 算法——Largest Rectangular Area in a HistogramLargest Rectangular Area in a Histogram
- [LeetCode]—Largest Rectangle in Histogram 求直方图最大填充矩形面积
- LeetCode | Largest Rectangle in Histogram(直方图围城的最大矩形面积)
- Largest Rectangle in Histogram 直方图中最大的矩形面积
- 【直方图的最大面积】Largest Rectangle in Histogram
- ACM-直方图最大面积-Largest Rectangle in Histogram
- LeetCode_直方图最大面积(Largest Rectangle in Histogram)
- LeetCode 84. Largest Rectangle in Histogram(直方图最大矩形)
- [Leetcode] largest rectangle in histogram 直方图中最大的矩形
- leetcode 84. Largest Rectangle in Histogram 最大直方图
- [IOS]联系人列表
- 企鹅2015校招笔试之(一)抽奖算法思路实现
- Android设置虚线、圆角、渐变
- ios开发优秀博客
- SVN服务端搭建 及eclipse中使用SVN
- 从LeetCode:Largest Rectangular Area in a Histogram(直方图最大面积) 说开去
- leetcode 6 ZigZag Conversion
- oc UI UIViewController的生命周期及iOS程序执行顺序
- Linux各个版本介绍
- 孪生蜘蛛
- Android系统上部署usb打印机
- ORA-00270: error creating archive log
- 第六周 项目四 成员函数、友元函数和一般函数有区别(3)一般函数
- 导航栏变化背景