1. 题目描述
难度:困难
2. 题目分析
这道题有两种解法,一种是暴力遍历法,一种是利用栈来进行的单调栈的方法。
- 暴力法
暴力法师很容易想到的方法,从左到右依次遍历数组,依次计算每个元素所构成的最大矩形面积。时间复杂度为O(n^2)。
- 单调栈
这是一个非常典型的利用单调栈来解决 顺序和大小综合问题的题。单调栈特别适合解决这些,两头大小决定中间值的大小的题。
因为单调栈中,以单调增栈为例。
设栈顶元素为 b, 栈顶第二个元素为a,自然有 a < b (因为堆栈越往上越大),这时候, 若c出现,且c小于b, 那么b的左右第一个比b小的两个元素就找到了,分别是a和c,b在中间最大。这时候你可以处理b,并重新整理堆栈,使其保持递增。若c大于b,那c入栈,继续循环就行了。最后清理堆栈。
这个题的关键点在于:
以B点为高的矩形的最大宽度为, 从a到c, 其中a,c分别为B左边和右边第一个小于B的元素。
单调栈的特点在于:
当遇见大数的时候, 压入堆栈,等待之后处理。
当遇见小数c的时候,意味着大数b的右边界c已经确定了。
这时候开始pop, 而以被pop出来的值(b)为高度的矩形的左右边界需要被确定。
其右边界就是当前的小数。即为c。左边界是堆栈下一层的元素,因为下一层的元素一定比当前小。且是第一小的元素。这时候a也确定了。
则以被pop出来的数为高度的矩形是 (c - a - 1) * pop(), 这里pop() == b
这里细节需要注意的是,
- 栈底要垫上**-1**,表示栈底。
- 循环结束,要清理堆栈。此时所有栈中继续存放的元素的右边界c都是结尾len(height)-1
3. C语言实现
3.1 暴力法
// 暴力法
int largestRectangleArea(int* heights, int heightsSize){
int i, j;
int max = 0;
int minHeight;
if(heightsSize == 1) return heights[0];
if(heightsSize == 0) return 0;
for(i = 0; i < heightsSize; i++){
minHeight = heights[i];
for(j = i; j < heightsSize; j++){
minHeight = minHeight < heights[j]? minHeight:heights[j];
max = max > minHeight*(j-i+1)? max: minHeight*(j-i+1);
}
}
return max;
}
运行结果为:
3.2 单调栈
代码如下:
int returnMax(int a, int b){
return a>b?a:b;
}
// 单调栈
int largestRectangleArea(int* heights, int heightsSize){
if(heightsSize == 0) return 0;
if(heightsSize == 1) return heights[0];
int* stack = (int *)malloc(sizeof(int)*(heightsSize+1));
int index = 0;
int max = 0;
int label;
stack[index] = -1;
for(int i = 0; i < heightsSize; i++){
while(index != 0 && heights[i] < heights[stack[index]]){
max = returnMax(max, heights[stack[index]]*(i-stack[--index]-1));
}
stack[++index] = i;
}
label = index;
while(index != 0){
max = returnMax(max, heights[stack[index]]*(stack[label]-stack[--index]));
}
return max;
}
运行结果为:
4. Java实现
单调栈代码实现如下:
public class Solution {
public int largestRectangleArea(int[] heights) {
Stack < Integer > stack = new Stack < > ();
stack.push(-1);
int maxarea = 0;
for (int i = 0; i < heights.length; ++i) {
while (stack.peek() != -1 && heights[stack.peek()] >= heights[i])
maxarea = Math.max(maxarea, heights[stack.pop()] * (i - stack.peek() - 1));
stack.push(i);
}
while (stack.peek() != -1)
maxarea = Math.max(maxarea, heights[stack.pop()] * (heights.length - stack.peek() -1));
return maxarea;
}
}
运行结果为: