您的位置:首页 > 其它

leecode 解题总结:84. Largest Rectangle in Histogram

2017-02-13 13:31 204 查看
#include <iostream>
#include <stdio.h>
#include <vector>
#include <set>
#include <stack>
using namespace std;
/*
问题:
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 heights = [2,1,5,6,2,3],
return 10.

分析:这道题目需要从矩阵图中找到面积最大的矩阵,矩阵条的高度等于数组中给定值的高度。
暴力破解:遍历每个bar,然后遍历高度1~h,对每个高度从当前一直到最后一个bar。
或者简单一点,罗列出每个起始bar和终止bar,然后设定高度为从起始bar到终止bar中高度的最小值
时间复杂度为O(n^2)。因为从一组数里选择最小的数时间复杂度为O(n)或者O(logN)用小丁对
但是不一定[low,high]的面积=(high-low+1)*minHeight,可能会是其他。
是否可以选定一个中心,然后向两边扩散。
如果中心的左边>右边,那么应该优先选择哪一边

有点累似盛水的题目,盛水从左和从右分别维持两个指针,和leftMax,rightMax,如果leftMax < rightMax,
以左边为基准。

未能解答出。

网上解法:
从左导游遍历所有bar,每个bar仅雅茹到栈一次。一个bar会被弹出,当前遇到一个较小高度的bar。当一个bar被弹出时,
我们计算弹出的bar的面积并作为最小的bar。如何获取弹出bar左边和右边的下标?
当前的下标告诉了我们右边的下标,而在栈中存储的前一个bar就是左边的下标。
步骤:
1】创建空栈,设直方图为hists[i],i从0到n-1。
2】如果栈为空,或者当前hists[i]>=栈顶高度,就压入i
否则,如果hists[i] < 栈顶对应元素高度,就移出栈顶,直到栈顶元素高度<=hist[i],
在此过程中不断计算面积,该面积是所有大于hists[i]的连续bar组成的矩阵面积

输入:
6(数组元素个数)
2 1 5 6 2 3

7
6 2 5 4 5 1 6
输出:
10
12
关键:
1 核心思想是:维护一个单调非递减的区间[low,high],而栈stack中存放了非递减区间的元素下标,一旦找到当前元素(对应下标为i)<栈顶元素,则开始计算面积
面积 = 当前高度 * (终点 - 起点 + 1),满足:终点对应元素高度>=当前高度,起点对应元素高度>=当前高度
由于是单调非递减区间
弹出一次栈顶,新的栈顶对应元素高度<=当前高度,那么新的栈顶记录的位置+1 对应元素高度 >= 当前高度【关键】
所以起点 = 新的栈顶记录的位置 + 1
终点 = i - 1
面积 = 当前高度 * (i - 1  - (新的栈顶记录的位置+1) + 1) = 当前高度 * ( i - 1 - 新的栈顶记录的位置)

//首先明确hists中存放了单调非递减区间对应高度的下标,所以heights[删除栈顶后的新top] <= heights[top]
while(i < n)
{
//当前元素高度>=栈顶元素高度,压入栈中。为的是寻找递增区间
if(hists.empty() || heights.at(i) >= heights[hists.top()] )
{
hists.push(i++);
}
//当前元素高度< 栈顶元素高度,开始计算最大面积
else
{
top = hists.top();//top是当前递增区间终止bar的下标,用于计算高度
hists.pop();//这里之所以要弹出,是因为
//宽度=i-1(递增高度最大值对应下标) - 弹出当前元素后的栈顶高度
if(hists.empty())
{
width = i;//表明0~i-1都是递增区间,长度为i
}
else
{
//这样理解i是第一个小于递增区间的下标。 i-1是递增区间的终止下标,那么hists.top()+1对应的是大于等于当前元素高度的起始结点下标
//宽度=终点-起点+1=i-1 - (hists.top() + 1) + 1 = i - 1 - hists.top()
width = i - 1 - hists.top();
}
area = heights.at(top) * width;//注意对应高度是top下标对应高度
if(area > maxArea)
{
maxArea = area;
}
}
}
*/

class Solution {
public:

int largestRectangleArea(vector<int>& heights) {
if(heights.empty())
{
return 0;
}
stack<int> hists;
int i = 0 ;
int n = heights.size();
int area;
int maxArea = INT_MIN;
int top;
int width;
//首先明确hists中存放了单调非递减区间对应高度的下标,所以heights[删除栈顶后的新top] <= heights[top]
while(i < n)
{
//当前元素高度>=栈顶元素高度,压入栈中。为的是寻找递增区间
if(hists.empty() || heights.at(i) >= heights[hists.top()] )
{
hists.push(i++);
}
//当前元素高度< 栈顶元素高度,开始计算最大面积
else
{
top = hists.top();//top是当前递增区间终止bar的下标,用于计算高度
hists.pop();//这里之所以要弹出,是因为
//宽度=i-1(递增高度最大值对应下标) - 弹出当前元素后的栈顶高度
if(hists.empty())
{
width = i;//表明0~i-1都是递增区间,长度为i
}
else
{
//这样理解i是第一个小于递增区间的下标。 i-1是递增区间的终止下标,那么hists.top()+1对应的是大于等于当前元素高度的起始结点下标
//宽度=终点-起点+1=i-1 - (hists.top() + 1) + 1 = i - 1 - hists.top()
width = i - 1 - hists.top();
}
area = heights.at(top) * width;//注意对应高度是top下标对应高度
if(area > maxArea)
{
maxArea = area;
}
}
}
//如果最后还有元素留在栈中,也必定是升序的,再计算一次
while(!hists.empty())
{
top = hists.top();
hists.pop();
if(hists.empty())
{
width = i;
}
else
{
width = i - 1 - hists.top();
}
area = heights.at(top) * width;
if(area > maxArea)
{
maxArea = area;
}
}
return maxArea;
}

//从数组中选择最大的数,如果用线性时间选择,选择的是前k个数,时间复杂度为O(logN)
//或者用堆来做,堆的实现应该是set,但是set你得先插入一遍数据,和直接遍历找出最小的一样。

int largestRectangleArea2(vector<int>& heights) {
if(heights.empty())
{
return 0;
}
int size = heights.size();
int maxArea = INT_MIN;
int minHeight = INT_MAX;
int area;
int beg = -1;
int end = -1;
//最后一个位置i能够取到
for(int i = 0 ; i < size  ; i++)
{
for(int j = i ; j < size ; j++)
{
minHeight = INT_MAX;
for(int k = i ; k <= j; k++)
{
//求出最小高度
if(heights.at(k) < minHeight)
{
minHeight = heights.at(k);
}
}
//求出面积
area = minHeight * (j - i + 1);
if(area > maxArea)
{
maxArea = area;
beg = i;
end = j;
}
}
}
return maxArea;
}
};

void print(vector<int>& result)
{
if(result.empty())
{
cout << "no result" << endl;
return;
}
int size = result.size();
for(int i = 0 ; i < size ; i++)
{
cout << result.at(i) << " " ;
}
cout << endl;
}

void process()
{
vector<int> nums;
int value;
int num;
Solution solution;
vector<int> result;
while(cin >> num )
{
nums.clear();
for(int i = 0 ; i < num ; i++)
{
cin >> value;
nums.push_back(value);
}
int result = solution.largestRectangleArea(nums);
cout << result << endl;
}
}

int main(int argc , char* argv[])
{
process();
getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: