84. 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.

Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

The largest rectangle is shown in the shaded area, which has area = 10 unit.
For example,
Given height = [2,1,5,6,2,3],
return 10.
链接: http://leetcode.com/problems/largest-rectangle-in-histogram/
题解:
也是一道难题。看过不少解答,最好的是维护一个递增栈(或者一个Deque), 当栈为空或者当前元素比栈顶元素大时,把当前元素入栈。否则把栈顶元素出栈,继续比较下一个栈顶元素与当前元素的大小。假如是1,2,3,4,1的话,运行到第2个1的时候,就要先出栈4,计算4 x 1,再是 3 x 2, 2 x 3,之后1 入栈, 最后遇到0计算 1 x 4。 一开始的array copy是为了创建最后一个数是0的情况,否则整个数组全部是递增的话没法pop()了。也要注意边界条件 - pop到最后时假如stack.isEmpty(), 则h[tmp] * i。
题外话: 上周五去草堂吃饭,点了一盘虎皮尖椒,吃完就胃部不适,过了一会整个胃灼烧感明显...让参加吃饭的各位扫兴了。最后是子龙兄在大雨中搀着我回家的,真是风雨同路人啊,感谢子龙兄!
Time Complexity - O(n), Space Complexity - O(n)。
public class Solution { public int largestRectangleArea(int[] height) { if(height == null || height.length == 0) return 0; int[] h = new int[height.length + 1]; h = Arrays.copyOf(height, height.length + 1); // last one is 0 so it's a pop() Stack<Integer> stack = new Stack<>(); int i = 0, max = 0; while(i < h.length){ if(stack.isEmpty() || h[stack.peek()] <= h[i]) // we use an increasing stack() stack.push(i++); else { int tmp = stack.pop(); //pop index in reverse order max = Math.max(max, h[tmp] * (stack.isEmpty() ? i : ((i - 1) - stack.peek()))); } } return max; } }
二刷:
跟一刷类似,主要还是维护一个递增栈。下面我们详细分析一下
- 递增栈的技术除了这道题以外,还从一本<挑战程序设计>上看到过,据说在ACM里很常用。
- 这里我们用一个LinkedList list来代替stack, 首先设定一个用来遍历的变量i,以及一个用来存储最后结果的max。
- 接下来在遍历的过程中,我们维护一个递增栈, 栈的内容是heights数组的index,栈底部的元素就是当前的最小值。
- 当栈为空,或者当前位置的heights[i]大于等于栈顶元素的值heights[list.peekLast()],我们把这个元素入栈,然后计算下一个元素
- 否则,当前位置的heights[i]小于栈顶元素的值,我们要pop出栈顶元素,然后尝试更新max
- 假如pop之后,栈为空,那么这时候我们就用heights[lastIndex] * i, 就是从头开始最小的元素
- 否则,我们用之前的位置i - 1,减去栈顶元素位置的值。 这个要好好计算一下
- 假如遍历结束以后,栈还不为空,那么我们使用跟5一样的代码,依次pop出栈顶元素并且尝试更新max
Java:
Time Complexity - O(n), Space Complexity - O(n)。
public class Solution {
public int largestRectangleArea(int[] heights) {
if (heights == null || heights.length == 0) {
return 0;
}
LinkedList<Integer> list = new LinkedList<>();
int i = 0, max = 0;
while (i < heights.length) {
if (list.size() == 0 || heights[i] >= heights[list.peekLast()]) {
list.addLast(i++);
} else {
int lastIndex = list.pollLast();
max = Math.max(max, heights[lastIndex] * (list.isEmpty() ? i : (i - 1) - list.peekLast()));
}
}
while (list.size() > 0) {
int lastIndex = list.pollLast();
max = Math.max(max, heights[lastIndex] * (list.isEmpty() ? i : (i - 1) - list.peekLast()));
}
return max;
}
}
三刷:
简化了一下code,但速度并不快。更快的方法是使用一个array来模拟栈的操作。
Java:
public class Solution { public int largestRectangleArea(int[] heights) { if (heights == null || heights.length == 0) return 0; Stack<Integer> stack = new Stack<>(); int max = 0, idx = 0; while (idx <= heights.length) { int curHeight = (idx != heights.length) ? heights[idx] : 0; if (stack.isEmpty() || curHeight >= heights[stack.peek()]) { stack.push(idx++); } else { int height = heights[stack.pop()]; int len = stack.isEmpty() ? idx : (idx - 1 - stack.peek()); max = Math.max(max, len * height); } } return max; } }
测试:
[2, 3, 4, 6, 7, 2]
[4, 2, 0, 3, 2, 5]
[1, 1, 1, 1, 2]
Reference:
http://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html
https://leetcode.com/discuss/8079/my-modified-answer-from-geeksforgeeks-in-java
https://leetcode.com/discuss/22431/o-n-stack-based-java-solution
https://leetcode.com/discuss/90454/5ms-o-n-java-solution-explained-beats-96%25
https://leetcode.com/discuss/103600/java-o-n-beats-96-42%25
https://leetcode.com/discuss/22431/o-n-stack-based-java-solution
https://leetcode.com/discuss/12780/my-concise-c-solution-ac-90-ms
https://leetcode.com/discuss/36608/my-concise-code-20ms-stack-based-o-n-one-trick-used
https://leetcode.com/discuss/91902/share-my-2ms-java-solution-beats-100%25-java-submissions
https://leetcode.com/discuss/70983/4ms-java-solution-using-o-n-stack-space-o-n-time

浙公网安备 33010602011771号