zoukankan      html  css  js  c++  java
  • LeetCode 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.

     

    示例

    Given heights = [2,1,5,6,2,3],
    return 10.

    解题思路

    第一阶段:

    拿到这种题,首先想怎么用最暴力的方法解决这个问题,于是自然而然的想出来枚举的方法,即利用二重循环枚举所有可能的区间,接着再这区间中找出最小的值,然后用(最小值 * 区间宽度)求出每个区间的最大值,最后从这些最大值中找出最大解。

     

    这种解法的时间复杂度是O(n^3),一般都会超时的,那么我们就会想着降低时间复杂度,即去冗余的方法(冗余分为重复计算和不需要计算两种)

    第二阶段:

    那么哪里存在冗余呢?第一个想到的应该是区间内求最小值时存在重复计算,我们可以使用空间换时间的方法将之前算过的最小值存储下来,这样求最小值[i][j] 就等于MIN( 最小值[i][j-1] ,  j) ,这样我们就时间复杂度降低到了O(n^2)

    第三阶段:

    通过推演又进一步发现了冗余的地方,比方说对于[9, 8, 10, 3, 12, 11,15]来说,虽然我们枚举了所有可能的区间,计算了其区间内的最小值,但你有没有发现,其中大多数的最小值都是 3, 那么我们能不能改变思路减少该冗余呢?

    于是乎我们可以采用枚举最小值的算法,即假设每一个点都是最小值,然后我们计算出其作为最小值可以向左右两边延伸的最大区间(如果该点左边的点值大于该点,则继续往左比较,知道某点比该点值小为止)

    最后可以算出每一个点作为最小值所包括的最大面积。面积 = n点高度 * (n右边界 - n左边界 + 1 ) 

    第四阶段:

    上一阶段的时间复杂度似乎并没有减少,那么肯定这种新思路引来了新的冗余,这种冗余在哪里呢?

    我们发现在找一个点的左右最大区间时存在重复计算,因为如果n点比n - 1点的值大的话,那么n点左边界应该大于等于n - 1点的左边界,于是乎我们可以存储下每个点的左右边界,避免很多重复计算

    最终思路:

    1. 枚举所有点,将其作为最小值
    2. 记录每个点的左右边界(计算n点左边界的方法是:判断n是否比n - 1小,如果成立则跳到n - 1 点的左边界x, 比较n是否比x小,如此循环,知道求出左边界
    3. 枚举每一个点的最大面积,计算最大解

    完整代码

    public class Solution {
        public int largestRectangleArea(int[] heights) {
            int n = heights.length;
            if (n == 0) {
                return 0;
            }
            // 求左边的边界
            int[] left = new int[n];
            left[0] = 0;
            for (int i=1;i<n;++i) {
                int A = i;
                while (A > 0 && heights[A - 1] >= heights[i]) {
                    A = left[A - 1];
                }
                left[i] = A;
            }
            // 求右边的边界
            int[] right = new int[n];
            right[n - 1] = n - 1;
            for (int i=n-2;i>=0;--i) {
                int A = i;
                while (A < n - 1 && heights[A + 1] >= heights[i]) {
                    A = right[A + 1];
                }
                right[i] = A;
            }
            // 枚举每一个最小值的最大面积
            int ans = 0;
            for (int i=0;i<n;++i) {
               ans = Math.max(ans, heights[i] * (right[i] - left[i] + 1));
            }
            return ans;
        }
    }
    

      

        

  • 相关阅读:
    [leetcode]66Plus One
    [leetcode]64Minimum Path Sum 动态规划
    [leetcode]62.UniquePaths
    [leetcode]54. Spiral Matrix2生成螺旋数组
    Keywords Search HDU
    Division HDU
    Naming Babies UVA
    Pearls POJ
    K-Anonymous Sequence POJ
    Post Office POJ
  • 原文地址:https://www.cnblogs.com/LiCheng-/p/6679097.html
Copyright © 2011-2022 走看看