柱状图中最大的矩形

力扣地址

单调栈:

按题目要求,需要知道每个位置的矩形可以扩展到的最远距离,由于比当前位置的值小的矩形是不可能与当前位置共同组成矩形的,

所以题目可以理解为,寻找当前位置的左右两边第一个比自己小的值,用这两个位置的 index 相减得到宽度,再乘以当前位置的长度,

如此得到当前位置的最大矩形面积,对每个位置都如此,寻找最大的矩形面积。

如此,我们只需要对数组左右个遍历一次,就可以知道每个位置的左右第一个比自己小的值的位置。

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int len = heights.size();
        if (!len) return 0;
        if (len == 1) return heights[0];
        vector<int> left(len, -1), right(len, len);
        vector<int> s;
        for (int i = 0; i < len; ++i) {
            while (s.size() && heights[s.back()] >= heights[i]) {
                s.pop_back();
            }
            left[i] = s.empty() ? -1 : s.back();
            s.push_back(i);
        }
        s.clear();
        for (int i = len - 1; i >= 0; --i) {
            while (s.size() && heights[s.back()] >= heights[i]) {
                s.pop_back();
            }
            right[i] = s.empty() ? len : s.back();
            s.push_back(i);
        }
        int res = 0;
        for (int i = 0; i < len; ++i) {
            res = max(res, heights[i] * (right[i] - left[i] - 1));
        }
        return res;
    }
};

优化一:

其实只需要一个 for 循环就可以获取到 left 和 right 数组

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int len = heights.size();
        if (!len) return 0;
        if (len == 1) return heights[0];
        vector<int> left(len, -1), right(len, len);
        vector<int> s;
        for (int i = 0; i < len; ++i) {
            while (s.size() && heights[s.back()] > heights[i]) {
                right[s.back()] = i;
                s.pop_back();
            }
            left[i] = s.empty() ? -1 : s.back();
            s.push_back(i);
        }
        int res = 0;
        for (int i = 0; i < len; ++i) {
            res = max(res, (right[i] - left[i] - 1) * heights[i]);
        }
        return res;
    }
};

优化二:

仔细看上面的操作会发现,其实我们既然可以在每次的for循环中获取到左右的值,其实就可以在for循环中直接判断了,这里我们需要用到两个哨兵,数组左右各一个,保证数组的有效性

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int len = heights.size();
        if (!len) return 0;
        if (len == 1) return heights[0];
        vector<int> v (len + 2, 0);
        for (int i = 0; i < len; ++i) {
            v[i + 1] = heights[i];
        }
        vector<int> s;
        s.push_back(v[0]);
        int res = 0;
        len += 2;
        for (int i = 1; i < len; ++i) {
            while (v[s.back()] > v[i]) {
                int height = v[s.back()];
                s.pop_back();
                int width = i - s.back() - 1;
                res = max(height * width, res);
            }
            s.push_back(i);
        }
        return res;
    }
};

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值