最近在刷leetcode,又碰到了这道题,想起来当时算法有些瑕疵,所以将最新的AC代码更新在最上面做个对比,具体思路见注释.
public class Solution {
// 思路: 主要是使用一个栈来保存数组元素的下标,注意是保存‘下标’。
// 入栈和出栈的规则如下:
// (1) 当栈为空,或者以栈顶元素tp为下标查到的heights[tp] <= heights[i]时(i为当前遍历的索引),入栈
// (2) 当栈顶元素tp对应的heights[tp] > heights[i]时,出栈,同时计算以heights[tp]为高,能得到的最大矩形面积
// (3) 当遍历完整个heights数组后,若栈不为空,则依次弹栈,同时以栈顶元素tp对应的heights[tp]为高,计算能得到的最大矩形面积
public int largestRectangleArea(int[] heights) {
if (heights == null || heights.length == 0) {
return 0;
}
Stack<Integer> stack = new Stack<Integer>();
int maxSize = 0;
int i = 0;
for (; i < heights.length; i++) {
if (stack.empty() || heights[stack.peek()] <= heights[i]) {
stack.push(i);
} else {
// 当前遍历元素heights[i] 比栈顶元素tp对应的heights[tp]小, 栈顶元素出栈
int tp = stack.pop();
int beginIndex = stack.empty() ? -1 : stack.peek(); // 当栈为空时,说明最大矩形的长度从下标0开始
// 所以将beginIndex设置为-1
maxSize = max(maxSize, heights[tp] * (i-1 - beginIndex));
i--; // 由于heights[i]元素还在栈外等候,还需要继续和栈顶元素进行比较,所以i--
}
}
while (!stack.empty()) {
// 栈还不为空,对每个栈顶元素tp 计算以heights[tp]为高的矩形的最大面积, 并将栈顶元素出栈
int tp = stack.pop();
int beginIndex = stack.empty() ? -1 : stack.peek(); // 当栈为空时,说明最大矩形的长度从下标0到下标n-1,
// 所以将beginIndex设置为-1
maxSize = max(maxSize, heights[tp] * (i-1 - beginIndex));
}
return maxSize;
}
private int max(int a, int b) {
return a > b ? a : b;
}
}
这次没有bug了 :)
@2016-03-07
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
最近在准备找工作,知道了这道题,用java实现了O(n)时间复杂度的算法。
具体题目如下:给一组非负的整数来表示一个柱状图,设计一个算法获得柱状图中最大矩形的面积。比如,输入如下数据:2,1,4,5,1,3,3 ,其中每个数表示一个柱状条的高度,柱状条的宽度为默认值1,则计算得最大矩形的面积为8。
思路:使用一个栈来保存输入柱状条,每个柱状条包含两个信息:(1)柱状条的高度(height);(2)柱状条的x坐标(index) 。数组中的柱状条按序准备入栈,入栈的条件:当入栈元素e的高度>=栈顶元素的高度时,元素e入栈;否则,将栈顶元素出栈,同时更新最大矩形maxValue的值。
更新maxValue的算法如下:
1. 计算以当前栈顶元素的高度为宽度的矩形的面积:tmpValue = topElement.height * (e.index - topElement.index);
2. 更新maxValue: maxValue = (maxValue > tmpValue) ? maxValue : tmpValue;
所有元素入栈完毕,将栈中剩余的元素依次出栈,同时按照相同的思路更新maxValue的值。
java实现:
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class MaxRectangle {
// 使用栈来保存每个柱状条,当当前准备入栈的柱状条的高度小于当前栈顶的柱状条高度时,先让栈顶元素出栈,同时计算最大的矩形大小
public int maxRectangleValue(int[] array) {
if (array == null || array.length <= 0)
return -1;
int maxValue = 0;
List<Element> inputList = new ArrayList<Element>();
int len = array.length;
for (int i = 0; i < len; i++) {
Element element = new Element(array[i], i);
inputList.add(element);
}
// 开始入栈操作
Stack<Element> stack = new Stack<Element>();
for (Element e : inputList) {
if (stack.empty())
stack.add(e);
else {
while (e.height < stack.peek().height) { // 出栈,并计算最大矩形大小
Element topElement = stack.pop();
int tmpValue = topElement.height * (e.index - topElement.index); // height * width
if (tmpValue > maxValue)
maxValue = tmpValue;
if (stack.empty())
break;
}
// 进栈
stack.add(e);
}
}
// 将堆栈中包含的所有元素出栈,同时更新最大的矩形大小
while (!stack.empty()) {
Element topElement = stack.pop();
int tmpValue = topElement.height * ((len - 1) - topElement.index + 1); // height * width
if (tmpValue > maxValue)
maxValue = tmpValue;
}
return maxValue;
}
public static void main(String[] args) {
int[] array = {2,1,4,5,1,3,3};
MaxRectangle mr = new MaxRectangle();
System.out.println(mr.maxRectangleValue(array));
}
}
class Element {
public int height; // 每一个柱状条的高度(宽度为1)
public int index; // 每个柱状条的x坐标值,代表它们出现的相对次序
public Element(int height, int index) {
this.height = height;
this.index = index;
}
}
算法分析:
所有数组元素需要一次进栈和一次出栈,所以总的时间复杂度为:O(n)