[LeetCode] 84. Largest Rectangle in Histogram

题: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

猜你喜欢

转载自blog.csdn.net/u013383813/article/details/80878664
今日推荐