[Leetcode] 85. Maximal Rectangle 解题报告

本文介绍了一种寻找二维二进制矩阵中只包含1的最大矩形的方法,并提供了三种实现思路:暴力枚举法、动态规划法及递增栈法。通过实例展示了不同算法的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area.

For example, given the following matrix:

1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 6.

思路

假设矩形的规模是m行n列,可以有如下三种基本思路:

1、暴力枚举法:一行一行的遍历数组,维护每个位置到顶部的高度,如果某位置高度大于0,就往回扫描到首列,同时维护一个当前最低的高度,这样就可以求出从这个位置到第一列的最大面积了。时间复杂度是O(m*n*n),当然通过转置可以优化到O(m*n*min(m, n)),但数量级不变。空间复杂度是O(n)。

2、动态规划法:由于在暴力枚举法中我们每碰到一个高度不为0的情况就往左搜索找到当前最低的高度然后更新面积,所以会导致重复计算。动态规划刚好可以通过记录原有信息来避免重复搜索。那么每一行我们需要记录什么呢?我们需要记录并维护的就是一行中每个位置高度的左右边界。

3、递增栈法:刚刚我们解决了“Largest Rectangle in Histogram”(Leetcode 85),这道题目可以看作是它的拓展,就是依次把每一行都当成一个柱形图的底,然后就可以直接采用Leetcode 85的思路了。

代码

1、暴力枚举法(46m):

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if(matrix.size() == 0) {
            return 0;
        }
        int m = matrix.size(), n = matrix[0].size();
        int ret = 0;
        vector<int> heights(n, 0);
        for(int i = 0; i < m; ++i) {
            for(int j = 0; j < n; ++j) {
                if(matrix[i][j] == '0') {
                    heights[j] = 0;
                    continue;
                }
                heights[j]++;
                int min_height = heights[j];
                for(int k = j; k >= 0; --k) {
                    min_height = min(heights[k], min_height);
                    ret = max(ret, (j - k + 1) *min_height);
                }
            }
        }
        return ret;
    }
};
2、动态规划法(13ms):

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if (matrix.size() == 0) {
            return 0;
        }
        int m = matrix.size(), n = matrix[0].size();
        int ret = 0;
        vector<int> heights(n,0), lefts(n, 0), rights(n, n);
        for (int i = 0; i < m; ++i) {
            int cur_left = 0, cur_right = n;
            for(int j = 0; j < n; ++j) {
                heights[j] = matrix[i][j] == '0' ? 0 : heights[j] + 1;
                if (heights[j] > 0) {
                    lefts[j] = max(lefts[j], cur_left);
                }
                else {
                    lefts[j] = 0;
                    cur_left = j + 1;
                }
            }
            for(int j = n - 1; j >= 0; --j) {
                if (heights[j] > 0) {
                    rights[j] = min(rights[j], cur_right);
                }
                else {
                    rights[j] = n;
                    cur_right = j;
                }
            }
            for(int j = 0; j < n; ++j) {
                ret = max(ret, (rights[j] - lefts[j]) * heights[j]);
            }
        }
        return ret;
    }
};
3、递增栈法(13ms):

class Solution {
public:
    int maximalRectangle(vector<vector<char>>& matrix) {
        if (matrix.size() == 0) {
            return 0;
        }
        int m = matrix.size(), n = matrix[0].size();
        int ret = 0;
        vector<vector<int>> ones(m + 1, vector<int>(n, 0));     // store the number of ones above directly
        for (int i = 1; i <= m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i - 1][j] == '1') {
                    ones[i][j] = ones[i-1][j] + 1;
                }
                else {
                    ones[i][j] = 0;
                }
            }
            ret = max(ret, largestRectangleArea(ones[i]));
        }
        return ret;
    }
private:
    int largestRectangleArea(vector<int>& heights)   
    {  
        if(heights.size() == 0) {  
            return 0;  
        }  
        stack<int> s;  
        heights.push_back(0);  
        int sum = 0;  
        for(int i = 0; i < heights.size(); ++i)  
        {  
            if(s.empty() || heights[i] > heights[s.top()]) {  
                s.push(i);  
            }  
            else  
            {  
                int tmp = s.top();  
                s.pop();  
                // width is the key point to understand this algorithm  
                int width = s.empty() ? i : i - s.top() - 1;  
                sum = max(sum, heights[tmp] * width);  
                i--;  
            }  
        }  
        return sum;  
    }
};





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值