LeetCode刷题之84-柱状图中最大的矩形

题目要求

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

思路1:暴力解法

解法一:固定宽度,依次遍历数组,找出最小高度h,即可得出面积值

private static int largestRectangleArea(int[] heights) {
      int res = 0;
      for(int left = 0; left < heights.length; left++){
          int minHeight = Integer.MAX_VALUE;
          for(int right = left; right < heights.length; right++){
              minHeight = Math.min(minHeight, heights[right]);
              res = Math.max(res, minHeight * (right - left + 1));
          }
      }
      return res;
}

该思路时间复杂度为O(n^{_{2}}),提交会超出时间限制

解法二:固定高度,依次遍历柱形的高度,对于每一个高度分别向两边扩散,求出以当前高度为矩形的最大宽度多少。

步骤:

  1. 左边看一下,看最多能向左延伸多长,找到大于等于当前柱形高度的最左边元素的下标;

  2. 右边看一下,看最多能向右延伸多长;找到大于等于当前柱形高度的最右边元素的下标。

  private static int largestRectangleArea(int[] heights) {
        int n = heights.length;
        if(n == 0){
            return 0;
        }
        int res = 0;
        for(int i = 0; i < n; i++){
            int left = i, right = i;
            int temp = heights[i];
            while (left > 0 && heights[left - 1] >= temp){
                left--;
            }
            while (right < n - 1 && heights[right + 1] >= temp){
                right++;
            }
            res = Math.max(res, temp * (right - left + 1));
        }
        return res;
    }

该思路时间复杂度为O(n^{_{2}}),提交会超出时间限制

思路二:栈(空间换时间)

暴力解法时间复杂度太高,那么如何能够一次遍历就得到结果?很容易就能想到的思路是空间换时间。

因为固定宽度已经使用了两重for循环,不易优化,所以我们考虑对固定高度的思路进行优化。

首先可以来考虑如何求出一根柱子左侧且最近的小于其高度的柱子。

对于两根柱子j1和j2,如果j1<j2并且heights[j1]\geqslant heights[j2],那么对于任意的在它们之后的柱子i(j2<i),j1一定不是i左侧且最近的小于其高度的柱子。

这样我们在枚举到第 i 根柱子的时候,就可以先把所有高度大于等于height[i]的 j值全部移除,剩下的 j值中高度最高的即为答案。在这之后,我们将 i放入数据结构中,开始接下来的枚举。此时,我们需要使用的数据结构就是栈。

具体步骤:

  • 栈中存放了 j 值。从栈底到栈顶,j 的值严格单调递增,同时对应的高度值也严格单调递增;
  • 当我们枚举到第 i 根柱子时,我们从栈顶不断地移除 height[j]≥height[i] 的 j值。在移除完毕后,栈顶的 j 值就一定满足height[j]<height[i],此时 j 就是 i 左侧且最近的小于其高度的柱子。

            这里会有一种特殊情况。如果我们移除了栈中所有的 j 值,那就说明 i 左侧所有柱子的高度都大于height[i],那么我们可以认为 ii 左侧且最近的小于其高度的柱子在位置 j=-1,它是一根「虚拟」的、高度无限低的柱子。这样的定义不会对 我们的答案产生任何的影响,我们也称这根「虚拟」的柱子为「哨兵」。

  • 我们再将 i 放入栈顶。
   private static int largestRectangleArea(int[] heights){
        int res = 0;
        Stack<Integer> stack = new Stack<>();
        int[] new_heights = new int[heights.length + 2];
        for (int i = 1; i < heights.length + 1; i++)
            new_heights[i] = heights[i - 1];
        System.out.println(Arrays.toString(new_heights));
        for (int i = 0; i < new_heights.length; i++) {
            System.out.println(stack.toString());
            while (!stack.isEmpty() && new_heights[stack.peek()] > new_heights[i]) {
                int cur = stack.pop();
                res = Math.max(res, (i - stack.peek() - 1) * new_heights[cur]);
            }
            stack.push(i);
        }
        return res;
    }

优化:利用一个单调递增的栈,找到left和right

    private static int largestRectangleArea(int[] heights) {
        Stack<Integer> stack = new Stack<>();
        int n = heights.length;
        int res = 0;
        int[] left = new int[n];
        int[] right = new int[n];
        for(int i = 0; i < n; i++){
            while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]){
                stack.pop();
            }
            left[i] = (stack.isEmpty()) ? -1 : stack.peek();
            stack.push(i);
        }
        stack.clear();
        for(int i = n - 1; i >= 0; i--){
            while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]){
                stack.pop();
            }
            right[i] = stack.isEmpty() ? n : stack.peek();
            stack.push(i);
        }
        for(int i = 0; i < n; i++){
            res = Math.max(res, heights[i] * (right[i] - left[i] -1));
        }
        return res;
    }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值