题目:

  给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。

以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]

 图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

 

题解:

  首先尝试暴力破解法,我们可以遍历每根柱子,以当前柱子 i 的高度作为矩形的高,那么矩形的宽度边界即为向左找到第一个高度小于当前柱体 i 的柱体,向右找到第一个高度小于当前柱体 i 的柱体。对于每个柱子我们都如上计算一遍以当前柱子作为高的矩形面积,最终比较出最大的矩形面积即可。暴力破解法效率较低,时间复杂度位O(N²),暴力法代码如下:

  

public int largestRectangleArea(int[] heights) {
        int area = 0, n = heights.length;
        // 遍历每个柱子,以当前柱子的高度作为矩形的高 h,
        // 从当前柱子向左右遍历,找到矩形的宽度 w。
        for (int i = 0; i < n; i++) {
            int w = 1, h = heights[i], j = i;
            while (--j >= 0 && heights[j] >= h) {
                w++;
            }
            j = i;
            while (++j < n && heights[j] >= h) {
                w++;
            }
            area = Math.max(area, w * h);
        }

        return area;
    }

  暴力破解法进行了2次遍历,那我们能不能使用一次遍历就求出来呢?那就需要使用单调栈来实现了,依次遍历heights[]数组,比较当前柱子高度和栈顶元素(高度)的大小,若比栈顶元素小则栈顶元素出栈计算面积,否则出栈。代码如下:

 public int largestRectangleArea(int[] heights) {
        Stack<Integer> stack = new Stack<>();//单调递增栈
        int[] newHeights = new int[heights.length+1];
        for(int i=0;i<heights.length;i++){
            newHeights[i] = heights[i];
        }
        int maxArea = 0;
        newHeights[heights.length] = 0;//末尾添0,作为出栈栈的最后一个元素使用
        for(int i=0;i<newHeights.length;i++){
            //比较当前元素和栈顶元素的大小,计算栈顶元素的最大矩形面积
            while(!stack.isEmpty() && newHeights[i] < newHeights[stack.peek()]){
                int top = stack.pop();//下标idx
                //新栈顶的下标是stack.peek()
                int width = i,height = newHeights[top];
                if(!stack.isEmpty()){
                    width = i-stack.peek()-1;
                }
                maxArea = Math.max(maxArea,height * width);
            }
            stack.add(i);
        }

        return maxArea;
    }

 

posted on 2021-10-23 17:54  李白菜  阅读(12)  评论(0编辑  收藏  举报