leetcode84--柱形图的最大面积

1. 题意

给定一个数组,求以数组中某一元素为高形成的连续矩形的最大面积。

转换成数学的描述就是

给定一个数组,求
a [ i : j ] m a x ( m i n { a [ i ] , a [ i + 1 ] ⋯   , a [ j ] } × ( j − i + 1 ) ) a[i:j]\\ max(min\{a[i],a[i+1]\cdots,a[j]\} \times(j-i+1)) a[i:j]max(min{a[i],a[i+1],a[j]}×(ji+1))

柱形图的最大面积

2. 题解

一个新的思路是,以数组中的某一元素进行扩展。

我们要找的即是,它左边第一个小于它高度的位置,和右边第一个小于它高度的位置。

只是这时刚好用到了数据结构单调栈而已。

  • 自己的解
    实际上就是把两步合成了一步。
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();

        stack<pair<int,int>> q;

        vector<int> left_first_min(n, -1);
        vector<int> right_first_min(n, n);

        q.push({0, heights[0]});
        for (int i = 1; i < n; ++i) {

        
            while (!q.empty() && q.top().second > heights[i]) {
                right_first_min[q.top().first] = i;
                q.pop();
            }


            if (q.empty() || q.top().second < heights[i]) {
                if (!q.empty()){
                    left_first_min[i] = q.top().first;
                }

            }
            else {
                left_first_min[i] = left_first_min[q.top().first];
            }
            q.push({i,heights[i]});
        }


        int ans = 0;
        for (int i = 0; i < n; ++i) {
            
            int tot = heights[i] * (right_first_min[i] - 
            left_first_min[i] - 1);
        
            ans = max(ans, heights[i] * 
            (right_first_min[i] - left_first_min[i] - 1));
        }






        return ans;
    }
};
  • 官解
    从左往右扫找到左边第一个小于它的位置;
    从右往左扫找到右边第一个小于它的位置。
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) 
    {
        
        int n = heights.size();

        vector<int> left(n, -1);
        vector<int> right(n, n);

        stack<int> p;
        for (int i = 0; i < n; ++i) {
            while (!p.empty() && heights[i] <= heights[p.top()]) {
                p.pop();
            }
            if (!p.empty())
                left[i] = p.top();
            p.push(i);
        }
        p = stack<int>();
        
        for (int i = n - 1; ~i; --i) {
            while (!p.empty() && heights[i] <= heights[p.top()])
                p.pop();
            if (!p.empty())
                right[i] = p.top();
            p.push(i);
        }

        // for (int i = 0; i < n; ++i) {
        //     std::cout << "l:" <<left[i] << "r:" << right[i] << std::endl;
        // }

        int ans = 0;

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


        return ans;
    }
};

官方还提供了两种暴力的方式,即枚举宽度和高度

  • 枚举区间
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        int ans = 0;
        // 枚举左边界
        for (int left = 0; left < n; ++left) {
            int minHeight = INT_MAX;
            // 枚举右边界
            for (int right = left; right < n; ++right) {
                // 确定高度
                minHeight = min(minHeight, heights[right]);
                // 计算面积
                ans = max(ans, (right - left + 1) * minHeight);
            }
        }
        return ans;
    }
};
  • 枚举高度
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        int ans = 0;
        for (int mid = 0; mid < n; ++mid) {
            // 枚举高
            int height = heights[mid];
            int left = mid, right = mid;
            // 确定左右边界
            while (left - 1 >= 0 && heights[left - 1] >= height) {
                --left;
            }
            while (right + 1 < n && heights[right + 1] >= height) {
                ++right;
            }
            // 计算面积
            ans = max(ans, (right - left + 1) * height);
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值