给出n个数字,代表直方图的条高,直方图每一条的宽度为1,请计算直方图中最大矩形的面积

上图是每条宽度为1, 高度 =[2,1,5,6,2,3].的直方图

图中的阴影部分是该直方图中面积最大的矩形,面积为10个单位
例如:
给出的高度 =[2,1,5,6,2,3],
返回10.
给出的高度 =[2,1,5,6,2,3],
返回10.
/*
用堆栈计算每一块板能延伸到的左右边界
对每一块板
堆栈顶矮,这一块左边界确定,入栈
堆栈顶高,堆栈顶右边界确定,出栈,计算面积
入栈时左边界确定
出栈时右边界确定
堆栈里元素是递增的
本质:中间的短板没有用!
复杂度 O(n)
*/
class Solution {
public:
int largestRectangleArea(vector<int> &height) {
int n=height.size(),result=0;
stack<int> s;
for(int i=0;i<n;++i){
while((!s.empty())&&(height[s.top()]>=height[i])){
int h=height[s.top()];
s.pop();
result=max(result,(i-1-(s.empty()?(-1):s.top()))*h);
}
s.push(i);
}
while(!s.empty()){
int h=height[s.top()];
s.pop();
result=max(result,(n-1-(s.empty()?(-1):s.top()))*h);
}
return result;
}
};
/* * Runtime: 24 ms.Your runtime beats 67.12 % of java submissions. */ public int largestRectangleArea(int[] heights) { if (heights == null || heights.length < 1) return 0; Stack<Integer> stack = new Stack<Integer>(); stack.push(-1); int max = 0; for (int i = 0; i < heights.length; i++) { while (stack.peek() != -1 && heights[i] < heights[stack.peek()]) { int top = stack.pop(); max = Math.max(max, (i - stack.peek() - 1) * heights[top]); } stack.push(i); } while (stack.peek() != -1) { int top = stack.pop(); max = Math.max(max, (heights.length - 1 - stack.peek()) * heights[top]); } return max; }
最简单的一个一个比较,时间复杂度比较大。如果使用堆栈时间复杂度会小很多。
public int largestRectangleArea(int[] height) {
int n = height.length;
int max = 0;
for(int i=0;i<n;i++){
int thisMinHeight = height[i];
int width = 0;
for(int j=i;j<n;j++){
width++;
thisMinHeight = Math.min(thisMinHeight,height[j]);
max = Math.max(max,thisMinHeight*width);
}
}
return max;
}
//以height的每个数作为基准来构建长方形,即从第i个值往前查找连续N个大于等于height[i]的值, //往后查找M个大于等于height[i]的值,即可以构建一个(M+N+1) * height[i]的长方形 //取其中面积最大的一个 public class Solution { public int largestRectangleArea(int[] height) { int max = 0; for(int i = 0; i < height.length; i++){ int len = 1; for(int j = i - 1; j >= 0; j--){ if(height[j] >= height[i]){ len++; }else { break; } } for(int k = i + 1; k < height.length; k++){ if(height[k] >= height[i]){ len++; }else { break; } } max = Math.max(max,len * height[i]); } return max; } }
//这里主要思路是遇到比上升序列就入栈,遇到下降序列就计算当前前一个直方图(即当前栈顶序号) //到所有依次出栈(即降序且大于j指向直方图的高度)直方图的距离,然后乘以出栈直方图的高度, //即为当前的面积(不一定最大),剩下的序列依然是升序的,迭代下去 class Solution { public: int largestRectangleArea(vector<int> &height) { int maxS = 0; int len = height.size(); stack<int> st; st.push(-1); int num; for(int i=0;i<len;i++) { while(st.top()!=-1 && height[i]<height[st.top()]) { num = st.top(); st.pop(); maxS = max(maxS,(i-1-st.top())*height[num]); } st.push(i); } while(st.top()!=-1) { num = st.top(); st.pop(); maxS = max(maxS,(len-1-st.top())*height[num]); } return maxS; } };
public int largestRectangleArea(int[] height) { int result=0; Stack<Integer> stack=new Stack<>(); int len=height.length; for(int i=0;i<len;i++){ //栈中存储的是递增高度对应的index if(stack.empty()||height[stack.peek()]<=height[i]) stack.push(i); else{ //碰到不满足递增的就干掉比当前高度大对应的index,直到当前高对应的index可以入栈 int high= height[stack.pop()]; //stack.peek()+1确定左边界,右边界是i,公式=高*(右边界-左边界) int width=stack.empty()?i:i-stack.peek()-1; result= Math.max(result,high*width); i--; } } while(!stack.empty()){ int index = stack.pop(); int high=height[index]; //之前***掉的也比当前的高度高,所以也被包括在左右边界之间 int width=stack.empty()?len:len-stack.peek()-1; result=Math.max(result,high*width); } return result; }
单调栈的最典型用法,下面的代码可以作为单调栈的模版进行记忆:
// // Created by jt on 2020/9/24. // #include <vector> #include <stack> using namespace std; class Solution { public: /** * * @param height int整型vector * @return int整型 */ int largestRectangleArea(vector<int>& height) { // write code here stack<int> stk; height.push_back(0); // 简化代码,确保栈最后会被清空 int maxVal = 0; for (int i = 0; i < height.size(); ++i) { while (!stk.empty() && height[i] < height[stk.top()]) { int h = height[stk.top()]; stk.pop(); int leftIdx = stk.empty() ? -1 : stk.top(); int w = i - leftIdx - 1; maxVal = max(maxVal, h * w); } stk.push(i); } return maxVal; } };
class Solution { public: int largestRectangleArea(vector<int> &height) { if(height.empty()) return 0; int maxarea=INT_MIN; set<int> ST(height.begin(),height.end()); for(set<int>::iterator i=ST.begin();i!=ST.end();i++) { int area=0; for(int j=0;j<height.size();j++) { if(height[j]>=*i) area+=*i; else { maxarea=max(maxarea,area); area=0; } } maxarea=max(maxarea,area); } return maxarea; } };用一个高度作为基准线,只要高于基准线,就将面积加上基准线高度;低于基准线就先将前面得到的面积储存起来,再继续测算; 这些基准线集合是包括整个数组里面不重复的值的集合,当把整个基准线集合计算完毕后,就可以得出最大面积。
/* 看了很久使用栈的题解,一直无法理解。 我这个贪心算法很容易理解。 遍历数组,认为当前值为答案的最低点。 向左找当前值大的,向右找比当前值大的。 */ public class Solution { public int largestRectangleArea(int[] height) { int len = height.length; if (len == 0) return 0; int width = 0; int left = 0, right = 0; int ans = Integer.MIN_VALUE; for (int i = 0; i < len; i++) { width = 1; left = i - 1; right = i + 1; while (left >= 0 && height[left] >= height[i]) { width++; left--; } while (right < len && height[right] >= height[i]) { width++; right++; } ans = Math.max(ans, height[i]*width); } return ans; } }
/****,先看到了上一道题,,,发现没有任何的思路,要怀疑人生,网上找各种解析
也发现根本看不懂,直到我点了下一道才发现要先坐着道题,这道题比上一道简单一
些,利用网上大神们的栈的思路,觉得非常吊记录一下思路:利用一个栈去实现将数组有序化,每次遍历数组都去与栈顶做对比,
如果发现比栈顶大则说明满足顺序直接入栈,如果没有栈顶元素值大,那就将栈顶出
栈,并计算当前result=max(result,count*top())。(注意这里,如果当前栈顶依然比较大,继续保
存result,弹出栈顶,此时的count值应该为当前栈顶元素值,在之前弹出的值都是比
该值大,计算面积的时候应该也计算到之前弹出的值。最后当所有元素遍历结束后,再
判断result中的值与直方图底部满足排序顺序的面积最大值进行对比即可
**/
class Solution {
public:
;
int largestRectangleArea(vector &height) {
int result = 0;
stack st;
for (auto it = height.begin(); it != height.end(); ++it)
{
if (st.empty() || st.top() <= *it)
st.push(*it);
else
{
int count = 0;
while (!st.empty() && st.top() > *it)
{
// [](int a, int b) -> bool { return a < b; }
count++;
result = result > count*st.top() ? result : count*st.top();
st.pop();
}
while (count-- > 0)
{
st.push(*it);
}
st.push(*it);
}
}
for (int i = 0; i < height.size(); i++)
{
int com = st.top() * (i+1);
st.pop();
result = result > com ? result : com;
}
return result;
}
};
//时间复杂度很大,不过自己写的 //加油 class Solution { public: int largestRectangleArea(vector<int> &height) { int len=height.size(); if(len<=0) return 0; int sum[1000][1000]={0}; int tem; int m=0; for(int i=0;i<len;i++){ sum[i][0]=height[0]; tem=height[i]; for(int j=i+1;j<len;j++){ tem=min(tem,height[j]); sum[i][j]=tem*(j-i+1); if(sum[i][j]>m) m=sum[i][j]; } } int ans= *max_element(height.begin(),height.end()); return ans > m ? ans:m; } };
//思路:单调栈 //维护一个单调递增的栈,l,r代表该pos的左右边界(l,r为下标) //例如:2,1,5,6,2,3 //2的左右边界为(0,0)即2在这个区间保持最小 //1就是(0,5) //最后算面积就是(p.r+1-p.l)*p.h class _103{ static class area{ int l; int r; int h; int index; } public int largestRectangleArea(int[] height) { area[] t=new area[height.length]; Stack<area> st=new Stack<area>(); for (int i = 0; i < height.length; i++) { t[i]=new area(); t[i].l=i; t[i].index=i; t[i].h=height[i]; } for (int i = 0; i < height.length; i++) { while (!st.isEmpty()&&st.peek().h>t[i].h){ t[st.peek().index].r=i-1; t[i].l=st.peek().l; st.pop(); } st.push(t[i]); } while (!st.isEmpty()){ st.pop().r=height.length-1; } int max=0; for (int i = 0; i < height.length; i++) { max=Math.max(max,(t[i].r+1-t[i].l)*t[i].h); } return max; } public static void main(String[] args) { int[] a={2,1,5,6,2,3}; System.out.println(new _103().largestRectangleArea(a)); } }
package largest_rectangle_in_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.
*/
public class Solution {
/**
* 暴力搜索,从左到右扫描边界,针对每个边界扫描左边的矩阵,计算面积,
* 注意保留最小高度和最大面积,时间复杂度 O(n^2)
*/
public int largestRectangleArea1(int[] height) {
if (height == null || height.length == 0)
return 0;
int maxArea = 0;
for (int boundary = 0; boundary < height.length; boundary++) {
int minHeight = height[boundary];
// 从右边界到左扫描计算面积,保存最大值
for (int left = boundary; left >= 0; left--) {
minHeight = Math.min(minHeight, height[left]);
int area = minHeight * (boundary - left + 1);
if (area > maxArea)
maxArea = area;
}
}
return maxArea;
}
/**
* 暴力搜索,从左到右扫描边界,针对每个边界扫描左边的矩阵,计算面积,
* 注意保留最小高度和最大面积,时间复杂度 O(n^2)
*/
public int largestRectangleArea(int[] height) {
if (height == null || height.length == 0)
return 0;
int maxArea = 0;
for (int boundary = 0; boundary < height.length; boundary++) {
// 暴力搜索优化的地方,对于 boundary 递增序列的情况,可 continue
if (boundary < height.length - 1 && height[boundary] <= height[boundary+1])
continue;
int minHeight = height[boundary];
// 从右边界到左扫描计算面积,保存最大值
for (int left = boundary; left >= 0; left--) {
minHeight = Math.min(minHeight, height[left]);
int area = minHeight * (boundary - left + 1);
if (area > maxArea)
maxArea = area;
}
}
return maxArea;
}
}
class Solution { public: int largestRectangleArea(vector<int> &height) { int n = height.size(); if(n == 0) return 0; vector<int> dp = height; int s = dp[0]; for(int i=1;i<n;i++) { int temp = height[i]; for(int j=i-1;j>=0 && height[j]>0;j--) { temp = min(temp,height[j]); dp[i] = max(dp[i],temp*(i-j+1)); } s = max(s,dp[i]); } return s; } };
/* 目的:用height[]构造一个升序栈,构造过程中计算面积; 如果当前height[i]大于栈顶元素,则入栈; 若小于栈顶元素,则将栈顶元素弹出并做记录弹出几次,并计算以弹出元素作为高度的面积,留下 最大值ret,直到满足height[i]大于栈顶元素,再将弹出的元素以height[i]重新入栈; 过程为 : 1)2入栈;目前栈为{2} 2)1与2比较,不满足升序,则2弹出,记录count=1;ret=2*1; 1代替2再次入栈,然后当前1入栈;目前栈为{1,1} 3)5入栈,满足升序,6入栈满足升序;目前栈为{1,1,5,6,} 4)height[4]=2,即将入栈,由于2小于栈顶元素6,则6弹出,count=1,ret=max(2,6)=6; 2小于5,5弹出,count=2,ret=max(6,2*5)=10; 6和5 重新以2入栈,然后height[4]=2入栈; 目前栈为{1,1,2,2,2} 5)height[5]=3入栈;形成升序栈{1,1,2,2,2,3} 6)最后按照升序栈继续维护ret直至栈为空,max(ret,3*1,2*2,2*3,2*4*,1*5,1*6)=10; */ class Solution { public: int largestRectangleArea(vector<int> &height) { int ret=0; stack<int> stk; for(int i=0;i<height.size();i++) { if(stk.empty()||(stk.top()<=height[i])) stk.push(height[i]); else { int count=0; while(!stk.empty()&&height[i]<stk.top()) { count++; ret=max(ret,count*stk.top()); stk.pop(); } while(count--) stk.push(height[i]); stk.push(height[i]); } } int count=1; while(!stk.empty()) { ret=max(ret,stk.top()*count); stk.pop(); count++; } return ret; } };
//类似于中心拓展法,针对每个位置,找到前后大于等于该高度元素的数量 public class Solution { /** * * @param height int整型一维数组 * @return int整型 */ public int largestRectangleArea (int[] height) { // write code here int max=0; int l=height.length; for(int i=0;i<l;i++){ int low=i; int high=i; int sum=-1; while(low>=0 && height[low]>=height[i]){ sum++; low--; } while(high<l && height[high]>=height[i]){ sum++; high++; } max=Math.max(max,sum*height[i]); } return max; } }
public int largestRectangleArea (int[] height) { if(height.length == 0 || height == null) return 0; int length = height.length; int max = 0; Stack<Integer> stack = new Stack<Integer>(); for(int i = 0 ; i < length ; i++){ while( !stack.isEmpty() && height[stack.peek()] >= height[i] ){ //矩形高度 int high = height[stack.pop()]; //矩形左边界 int leftIndex = stack.isEmpty() ? -1 : stack.peek() ; //矩形右边界 int rightIndex = i - 1; //计算面积 int curMax = high * (rightIndex - leftIndex ); max = Math.max(max,curMax); } stack.push(i); } //当右边无比 栈顶 小的数时,剩余数全入栈,此时上面的循环未将栈中元素pop,即有矩形高度为height[stack.peek()]的元素未计算面积最大值 while(!stack.isEmpty()){ //矩形高度 int high = height[stack.pop()]; //矩形左边界 int leftIndex = stack.isEmpty() ? -1 : stack.peek() ; //矩形右边界 int rightIndex = length - 1; //计算面积 int curMax = high * (rightIndex - leftIndex ); max = Math.max(max,curMax); } return max; }
class Solution { public int largestRectangleArea(int[] heights) { Stack<Integer> stack=new Stack<>();//栈 维护宽度 stack.push(-1);//入一个-1保证最小 int maxarea=0; for(int i=0;i<heights.length;++i){ while(stack.peek()!=-1&&heights[stack.peek()]>=heights[i])//如果这个比栈顶小,栈顶出栈,更新maxarea maxarea = Math.max(maxarea, heights[stack.pop()] * (i - stack.peek() - 1)); stack.push(i);//i入栈,成为现在栈顶,也是最大 } while(stack.peek()!=-1)//边界 全出 maxarea=Math.max(maxarea,heights[stack.pop()]*(heights.length-stack.peek()-1)); return maxarea; } }