1、直方图的最大矩形面积
问题:直方图是由排列在同一基线上的一系列矩形组成的多边形。为了简单起见,假设这些矩形的宽度相等但高度可能不同。例如,下图1给出了一个直方图,其中各个矩形的高度为3、2、5、6、1、4、4,宽度为标准1单位。当给定了一个保存所有矩形高度的数组时,如何找到其中最大的矩形。
对于给定的例子,最大矩形如图阴影部分所示:
时间复杂度和空间复杂度:O(n)
#include<iostream>
#include<stack>
#include<vector>
#include<math.h>
using namespace std;
int maxArea(vector<int> a) {
stack<int> stk;int cur,leftIdx,area,maxArea;
cur=leftIdx=area=maxArea=0;
for (int i=0; i<a.size()-1; i++) {
while(!stk.empty() && a[i]<=a[stk.top()]) {//注意<=
cur = stk.top();
stk.pop();
//cout<<"弹出cur="<<cur<<",值="<<a[cur]<<endl;
leftIdx = stk.empty()?-1:stk.top();
area = (i-leftIdx-1)*a[cur];
maxArea = max(area, maxArea);
}
stk.push(i);
//cout<<"压入i="<<i<<",值="<<a[i]<<endl;
}
while (!stk.empty()) {
cur = stk.top();
stk.pop();
leftIdx = stk.empty()?-1:stk.top();
area = (a.size()-leftIdx-1)*a[cur];
maxArea = max(area, maxArea);
}
return maxArea;
}
int main() {
int n;cin>>n;vector<int> a(n, 0);
for (int i=0; i<n; i++) cin>>a[i];
int res = maxArea(a);
cout<<res;
return 0;
}
/*
输入如下:
7
3 2 5 6 1 4 4
输出如下:
10
*/
2、矩形的最大矩阵大小
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
依次以矩阵每一行j为底,往j-1结算每一列有多少个连续的1,将结果存在一个数组height[j]。例如以矩阵这行[1,1,1,1,1]往上几行结算,可得height[j]={3,1,3,2,2}。对于每次结算得到height[j]数组,我们可以将其看成一个直方图。如[3,1,3,2,2]可以看成直方图
第一行: height[j]={1,0,1,0,0},单调栈算出maxArea=1
第二行: height[j]={2,0,2,1,1},单调栈算出maxArea=3
第三行: height[j]={3,1,3,2,2},单调栈算出maxArea=6
第三行: height[j]={4,0,0,3,0},单调栈算出maxArea=4
综上,maxArea=6
public class MaxRectangelWith1 {
public static int maxRecSize(int[][] map){
if(map == null || map.length == 0 || map.length == 0){
return 0;
}
int maxArea = 0;
// 有多少列,就生成多大的长度
int[] heights = new int[map[0].length];
// 必须以第i行做底的情况下的直方图数组
for(int i = 0; i < map.length; i++){
for(int j = 0; j < map[0].length; j++){
// 如果当前位置为0,则直接置0,否则置1
heights[j] = map[i][j] == 0 ? 0 : heights[j] + 1;
}
// 得到直方图中的最大值(计算以每一行为底时的最大面积,最后取最大返回)
maxArea = Math.max(maxRecFromBottom(heights), maxArea);
}
return maxArea;
}
// heights代表直方图数组,返回其中最大的长方形面积,可能包含重复值
public static int maxRecFromBottom(int[] heights){
if(heights == null || heights.length == 0){
return 0;
}
int maxArea = 0;
Stack<Integer> stack = new Stack<>();
for(int i = 0; i < heights.length; i++){
// = 相等的时候是是算错了,但最后一个会算对,所以没关系
while(!stack.isEmpty() && heights[stack.peek()] >= heights[i]){
int current = stack.pop();
int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
// 以当前heights[current]为高度的最大矩形面积
int curArea = (i - leftLessIndex - 1) * heights[current];
maxArea = Math.max(maxArea, curArea);
}
stack.push(i);
}
// 遍历完了,但是栈中还有元素,要单独结算,R->height.length
while(!stack.isEmpty()){
int current = stack.pop();
int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
int curArea = (heights.length - leftLessIndex - 1) * heights[current];
maxArea = Math.max(maxArea, curArea);
}
return maxArea;
}
public static void main(String[] args) {
int[][] map = { { 1, 0, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 0 }};
System.out.println(maxRecSize(map));
}
}
3、可见山峰问题