题:https://leetcode.com/problems/largest-rectangle-in-histogram/description/
题目
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.
Example:
Input: [2,1,5,6,2,3]
Output: 10
思路
想法:
1.每一个可能成为最大的矩形,它的高度必定是数组中的某个数值。
2.现在的问题是如何求位置i 它对应的长度,两边都要小于heights[i]
3.对于每个i 左右扫描会造成 O(n^2),会报错。现在问题是如何降低时间复杂度。
4.这里引入一个减少时间复杂度的新思想。i的左右边界,可以看它最相邻i-1的左边界和i+1的右边界。边界还可以一直传递下去,只要边界的高度大于i的高度。
引用 Discuss中大神的解释,讲的十分清楚
https://leetcode.com/problems/largest-rectangle-in-histogram/discuss/28902/5ms-O(n)-Java-solution-explained-(beats-96)
For any bar i the maximum rectangle is of width r - l - 1 where r - is the last coordinate of the bar to the right with height h[r] >= h[i] and l - is the last coordinate of the bar to the left which height h[l] >= h[i]
So if for any i coordinate we know his utmost higher (or of the same height) neighbors to the right and to the left, we can easily find the largest rectangle:
int maxArea = 0;
for (int i = 0; i < height.length; i++) {
maxArea = Math.max(maxArea, height[i] * (lessFromRight[i] - lessFromLeft[i] - 1));
}
The main trick is how to effectively calculate lessFromRight and lessFromLeft arrays. The trivial solution is to use O(n^2) solution and for each i element first find his left/right heighbour in the second inner loop just iterating back or forward:
for (int i = 1; i < height.length; i++) {
int p = i - 1;
while (p >= 0 && height[p] >= height[i]) {
p--;
}
lessFromLeft[i] = p;
}
The only line change shifts this algorithm from O(n^2) to O(n) complexity: we don’t need to rescan each item to the left - we can reuse results of previous calculations and “jump” through indices in quick manner:
while (p >= 0 && height[p] >= height[i]) {
p = lessFromLeft[p];
}
CODE
from collections import defaultdict
class Solution:
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
if len(heights) == 0:
return 0
lessFromLeft = {}
lessFromRight = {}
lessFromLeft[0] = -1
lessFromRight[len(heights) - 1] = len(heights)
for i in range(1,len(heights)):
p = i - 1
while p>=0 and heights[p]>=heights[i]:
p = lessFromLeft[p]
lessFromLeft[i] = p
for i in range(len(heights)-2,-1,-1):
p = i + 1
while p<=len(heights)-1 and heights[p]>= heights[i]:
p = lessFromRight[p]
lessFromRight[i] = p
MaxArea = 0
for i in range(0,len(heights)):
MaxArea = max(MaxArea,heights[i]*(lessFromRight[i]-lessFromLeft[i]-1))
return MaxArea
超时版本 没有扫描优化
class Solution:
def largestRectangleArea(self, heights):
"""
:type heights: List[int]
:rtype: int
"""
maxsqr = 0
for i in range(len(heights)):
li = i
lr = i + 1
while li-1 >= 0 and heights[li-1] >= heights[i]:
li -= 1
while lr < len(heights) and heights[lr] >= heights[i]:
lr += 1
tmpsqr = (lr - li)*heights[i]
if tmpsqr > maxsqr:
maxsqr = tmpsqr
return maxsqr