单调栈(likou84. 柱状图中最大的矩形、likou85)

84. 柱状图中最大的矩形

难度 :困难

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

求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例 1:

输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10

第一种暴力解法:

就是向左右找大于等于自身高的最长宽度,这样求得的一定就最优解,不过时间复杂度太高,题目通过不了

    public int largestRectangleArea(int[] heights) {
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < heights.length; i++) {
            int count = 1;
            for (int j = i-1;j >= 0;j--){
                if (heights[j] >= heights[i]){
                    count++;
                }else {
                    break;
                }
            }

            for (int j = i+1; j < heights.length; j++) {
                if (heights[j] >= heights[i]){
                    count++;
                }else {
                    break;
                }
            }
           max = Math.max(max,count*heights[i]);
        }
        return max;
    }

第二种:解法单调栈,利用的栈的特点,实现找到左右端大于等于自身高的宽度。

 代码用的双向队列,其实就是双向队列就是栈,一般写题的大家都是用双向队列,可以是因为双向队列比较灵活吧,底层都是数组,

这个栈应该反过来的,在网上找到

    public int largestRectangleArea(int[] heights) {
        int n = heights.length;
        int[] left = new int[n];
        int[] right = new int[n];

        Deque<Integer> mono_stack = new ArrayDeque<Integer>();
        for (int i = 0; i < n; ++i) {
            while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
                mono_stack.pop();
            }
            left[i] = (mono_stack.isEmpty() ? -1 : mono_stack.peek());
            mono_stack.push(i);
        }

        mono_stack.clear();
        for (int i = n - 1; i >= 0; --i) {
            while (!mono_stack.isEmpty() && heights[mono_stack.peek()] >= heights[i]) {
                mono_stack.pop();
            }
            right[i] = (mono_stack.isEmpty() ? n : mono_stack.peek());
            mono_stack.push(i);
        }

        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans = Math.max(ans, (right[i] - left[i] - 1) * heights[i]);
        }
        return ans;
    }

代码的大概意思是:看图就知道。

int nums = new int[]{2,1,5,6,0,2,3}

打个比喻,就像一群人站一排 比较智商,每个人只能向前看,不能向后看,也就是说不知道身后的人的智商有多高,当找到比自己低的人(知道找到比自己智商低的人,或者是自己)

,我们创建一个房间,房间无限长,宽度只能站下一个人。

nums 数组中是每个人的身高。(所有人都是通过i的脚标放入stack中,这样方便取值)

A智商为2的先进人房间,因为(栈为空,说明是自己目前位置最低的,所以标记为Left = -1)

B智商为1的进入房间,这时房间内有一个人比自己智商高(去掉那些智商高的人,进入房间)(所以标记为Left = -1)

C智商为5进入房间,发现B在房间里,B的智商为1,(因为1比5小所以取值为Left = 1)C 进入房间(为了后面的人找到前面智商低的人,所以需要进入栈中)

D智商为6 进入房间(同C Left = 2)

E智商为0 进入房间,发现D比自己高(弹出,发现C比自己高,弹出,发现B比自己高,弹出,发现房间中没有人了,那么 Left = -1)自己进入房间 (并标记自己为最左边的)

F智商为2进入房间,发现房间中存在E智商为0,Left = 4 ,进入房间

G智商为3进入房间,发现房间中存在F智商为2,Left = 5 ,进入房间

int[] Left = {-1 , -1,1,2,-1,4,5}

ABCDEFG只跟比自己智商高的人玩耍,E可以和前面的所有人玩,B也可以和前面的所有人玩,D前面没有能和自己玩的,同理可以找到right可以和自己玩的人,就可以求出这段区间的面积了

感觉有并查集的味

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值