Largest Rectangle in Histogram
题目描述
给定一个整形数组,数组中每个元素代表一个矩阵其宽度都为1,而高度为数组对应位置的元素值,求这个数组矩阵组合的最大面积(两个相邻矩阵可以合并为一个宽度为2高为两个矩阵较小高的矩阵,依次类推)
例如给出如下矩阵[2,1,5,6,2,3]其最大面积值为5 * 2 = 10
解题思路
通常情况下本题的第一个思路就是暴力破解法,遍历数组对每个元素使用穷举所有可能组合的方式找到它的最大值,其复杂度为O(n2)。
为了得到更高效的算法我们首先对本题考虑一种特殊情况,假设数组元素是递增(或者递减)有序的,即数组arr(a0,a1,…..an-2,an)有a0 < a1 < ….. < an-2 < an。这样要找出最大值只要进行如下判断即可(高度一定时,宽度尽可能长)
对于上面的判断很明显我们只要遍历一遍数组得到每个位置代表高度的元素的值即可,即复杂度为O(n)。
那么由于题目中给出的数组是无序的,为了使得我们能按照上述思路来进行,从而获得一个O(n)的解法我们需要借助一个数据结构来使得我们能得到一个有序的序列从而方便进行判断。
我们利用一个整形临时变量记录当前最大面积,同时使用一个栈来保存遍历的元素,从而实现有序的判断。遍历数组时如果当前栈为空或者栈顶元素小于当前遍历元素则当前元素的下标入栈,这样栈中元素是一个递增有序的序列。反之,如果当前遍历元素小于栈顶元素那么以当前栈顶元素为高的矩阵最大宽度已经找到了,出栈栈顶元素获得高度乘上宽度得到其最大面积与当前最大面积比较来更新当前最大面积。完成遍历后即可得到答案。
代码
public static int largestRectangleArea(int[] height) {
int len = height.length;
//申请一个栈
LinkedList<Integer> s = new LinkedList<>();
//记录当前最大面积
int maxArea = 0;
for(int i = 0; i <= len; i++){
//获取当前遍历位置代表高度,
//在i==len时为了将栈中剩余元素出栈计算设当前高为0,
//因为0一定小于其他高度。
int h = (i == len ? 0 : height[i]);
if(s.isEmpty() || h >= height[s.peek()]){
s.push(i);
}else{
int tp = s.pop();
//i - 1 - s.peek()是计算宽度
maxArea = Math.max(maxArea, height[tp] * (s.isEmpty() ? i : i - 1 - s.peek()));
i--;//因为是小于栈顶元素没有入栈,继续比较当前元素
}
}
return maxArea;
}
这里解释一下宽度的计算i - 1 - s.peek();以数组[2,1,5,6,2,3]为例,当i = 4时栈中元素为[1,2,3] (下标),那么对于下标3代表的高度为6的矩阵最大宽度就可以得到了(当前遍历元素小于6),为i(=4) - 1 - 2,(此时3已经出栈了),那么这次判断做完后继续判断当前元素(下标4)与栈顶关系,因为当前遍历元素仍小于栈顶下标代表的元素,所以出栈得到高度为5的矩阵最大长度为i(=4) - 1 - 1 = 2。