LintCode 510: Maximal Rectangle

LintCode 510: Maximal Rectangle

题目描述

给你一个二维矩阵,权值为False和True,找到一个最大的矩形,使得里面的值全部为True,输出它的面积

Wed Nov 24 2016

思路

本题的思路比较多,可以用动态规划,也可以把本题看做是最长连续正数列的二维版本,还可以把本题看做多个求柱形图中得最大矩形问题。

如果用动态规划,记\(f(i, j, l)\)为以\((i, j)\)为左上角顶点,以\(l\)为列宽的矩形面积。指定\(i\)\(j\),通过变换\(l\),可以得到以\(i\)\(j\)为顶点的最大矩形面积。通过遍历\(i\)\(j\),可求出最终答案。此方法的时间复杂度为\(O(mn^2)\)

对于连续最长正数列,只需从头到尾遍历一遍即可,用一个变量记录当前最大的长度,当遇到0时重置长度计数。应用到二维情况则是遍历左上角顶点和右下角顶点,时间复杂度是\(O(m^2n^2)\)

对于在柱状图中求最大矩形,可以构造一个递增栈,使得求解的时间复杂度为\(O(n)\),应用到二维情况就是\(O(mn)\)

在一维的问题中,给的数据是一个数列,第i个数表示第i个位置的柱形的高度。从数列的第一个数开始,依次将它们入栈,直到当前准备入栈的高度小于栈顶元素的高度为止。这样就维护了一个递增的序列。

此时就可以计算一次矩形的面积了。矩形的高度就是当前栈顶元素位置柱状图的高度,矩形的宽度就是从当前准备入栈却又没有入栈的元素的位置到栈顶的距离。同时栈顶元素出栈。

若栈顶出栈后当前准备入栈的元素高度还是小于当前栈顶元素的高度,则继续出栈,计算方法跟上面的一样,之所以可以直接用当前准备入栈又还没入栈的元素与栈顶元素的距离来表示矩形的宽度,是因为当前栈顶的元素是从栈顶到准备入栈元素之间所有柱状图中高度最矮的(比它高的都出栈了)。

如此循环,直到当前元素的高度比栈顶元素的高度高了,再正常入栈。

此方法中每个元素只有一次机会入栈,所以时间复杂度是\(O(n)\)

应用到二维的问题中,其实就是把矩阵看作是多个柱状图的叠加。对于每一行,把那一行作为柱状图的横坐标,那一行以上1的个数就是该位置柱形的高度,那一行以下的部分忽略不计。在计算高度的时候,若某位置的元素是1,则该位置的高度等于上一行相同位置的高度加1,否则就直接是0。这样计算高度的算法的时间复杂度也是\(O(mn)\),总体的时间复杂度不变。

代码

// 从矩形中计算各个柱状图的高度
void getBarHeights(vector<vector<bool> > &matrix, vector<vector<int> > &heights)
{
    int n = matrix.size();
    int m = matrix[0].size();
    vector<int> tmp;
    for (vector<bool>::iterator iter = matrix[0].begin(); iter != matrix[0].end(); ++iter)
        tmp.push_back(*iter);
    heights.push_back(tmp);
    for (int i = 1; i < n; ++i)
    {
        for (int j = 0; j < m; ++j)
        {
            if (matrix[i][j] == 0)
                tmp[j] = 0;
            else
                tmp[j]++;
        }
        heights.push_back(tmp);
    }
}

// 柱状图求最大矩形算法
int maxBarRec(vector<int>& height)
{
    int max = 0;
    int n = height.size();
    stack<int> s;
    for (int i = 0; i <= n; ++i)
    {
        int h = i == n ? 0 : height[i];
        if (s.empty() || h > height[s.top()]) s.push(i);
        else
        {
            while (!s.empty() && h <= height[s.top()])
            {
                int crr = s.top(); s.pop();
                int area = height[crr] * (s.empty() ? i : i - s.top() - 1);
                if (area > max) max = area;
            }
            --i;
        }
    }
    return max;
}

// 主函数
int maximalRectangle(vector<vector<bool> > &matrix)
{
    int m = matrix.size();
    if (m <= 0) return 0;
    int n = matrix[0].size();
    int max = 0;
    vector<vector<int> > heights;
    getBarHeights(matrix, heights);
    for (int i = m - 1; i >= 0; --i)
    {
        int tmax = maxBarRec(heights[i]);
        if (tmax > max) max = tmax;
    }
    return max;
}

原文链接: https://www.cnblogs.com/genkun/p/6095504.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    LintCode 510: Maximal Rectangle

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/244482

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月14日 上午12:09
下一篇 2023年2月14日 上午12:09

相关推荐