203、【栈与队列】leetcode ——剑指 Offer II 040. 矩阵中最大的矩形 / 85. 最大矩形:暴力+单调栈(C++/Pyhont版本)

题目描述

在这里插入图片描述
在这里插入图片描述

Problem: 剑指 Offer II 040. 矩阵中最大的矩形

解法一:暴力解法

思路

首先, 按行获取到达某一元素位置时,之前与当前连续1的个数,这个连续1的个数就会作为所求矩阵的备选宽度。然后, 再迭代遍历,以列不变的基础上,从当前位置开始,自下而上改变行的位置,将原始位置与改变位置之差作为目标矩阵的备选长度,最后求得最大矩阵面积。

解题方法

计算矩阵宽度时,先以当前位置连续1的个数作为宽度,在后续更新时,因为要保证这个矩阵范围内都可以被囊括,就以迭代遍历中的最小宽度作为矩阵宽度。

计算矩阵面积时,用宽度乘以当前遍历到的行数之差,找出和已有结果对比的最大值,作为最大面积。

复杂度

  • 时间复杂度:

O ( m 2 n ) O(m^2n) O(m2n)
其中 m 和 n 分别是矩阵的行数和列数。计算 left 矩阵需要 O ( m n ) O(mn) O(mn)的时间。随后对于矩阵的每个点,需要 O(m) 的时间枚举高度。故总的时间复杂度为 O ( m n ) + O ( m n ) ⋅ O ( m ) = O ( m 2 n ) O(mn)+O(mn)⋅O(m)=O(m^2n) O(mn)+O(mn)O(m)=O(m2n)

  • 空间复杂度:

O ( m n ) O(mn) O(mn)
其中 m 和 n 分别是矩阵的行数和列数。我们分配了一个与给定矩阵等大的数组,用于存储每个元素的左边连续 1 的数量。

Code

C++


class Solution {
public:
    int maximalRectangle(vector<string>& matrix) {
        int m = matrix.size();
        if(m == 0)                  return 0;
        int n = matrix[0].size();
        vector<vector<int>> left(m, vector<int>(n, 0));
        for(int i = 0; i < m; i++) {                                    // 记录每行中连续1的个数
            for(int j = 0; j < n; j++) {
                if(matrix[i][j] == '1') {
                    left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;
                }
            }
        }

        int res = 0;
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                if(matrix[i][j] == '0') {                           // 遇到0说明不是矩阵,则直接跳出
                    continue;
                }
                int width = left[i][j];                             
                int area = width;                                   // 此时的面积是以长度=1,宽度=left[i][j],得到的面积
                for(int k = i - 1; k >= 0; k--) {                   // 因为之前记录的是每行连续的1(也就是长度),因此这里需要变化的是的整体的行长(宽度),从i-1开始
                    width = min(width, left[k][j]);                 // 找到当前范围内的最小宽度,遍历每种范围内的情况
                    area = max(area, (i - k + 1) * width);          // 获取当列不变时,行从0~i之间的最大面积
                }
                res = max(res, area);                               // 找到整体的最大面积
            }
        }

        return res;

    }
};

Python

class Solution:
    def maximalRectangle(self, matrix: List[str]) -> int:
        m = len(matrix)
        if m == 0:
            return 0
        n = len(matrix[0])
        left = [[0 for _ in range(n)] for _ in range(m)]        
        res = 0
        for i in range(m):
            for j in range(n):
                if matrix[i][j] == '1':
                    left[i][j] = left[i][j - 1] + 1 if j != 0 else 1
        for i in range(m):
            for j in range(n):
                width, area = left[i][j], left[i][j]
                for k in range(i - 1, -1, -1):
                    width = min(width, left[k][j])
                    area = max(area, (i - k + 1) * width)
                res = max(res, area)    

        return res

参考文章:矩阵中最大的矩形

解法二:单调栈解法

思路

按行遍历,将每列连续的1变成直方图。连续1的个数,作为直方图的高度,每到一行的时候就遍历该行情况下直方图中的最大矩阵。以此方式,遍历完所有的行,得到全局的最大矩阵。其实就相当于是 188、【栈与队列】leetcode ——84. 柱状图中最大的矩形:暴力解法+单调栈(C++/Python版本) 的拓展。

解题方法

采用与柱状图中的最大矩阵相同的方式,只不过本体将其扩展成了二维的形式。按行遍历,每行在遍历各列的时候,就相当于是探寻一个柱状图中的最大矩形

对每个直方图的首尾位置都先加一个0作为哨兵,也就是在矩阵中的首尾两列加入0。然后,以在上一行的基础上计算当前行的直方图高度。最后,遍历每一行,在每一行中使用计算柱状图中最大的矩形的方式,计算每行中的最大矩形,最后再找到各行中柱状图中的最大矩形,从而得到答案。

复杂度

  • 时间复杂度:

添加时间复杂度, 示例: O ( m n ) O(mn) O(mn)

  • 空间复杂度:

添加空间复杂度, 示例: O ( m n ) O(mn) O(mn)

Code

C++


class Solution {
public:
    int maximalRectangle(vector<string>& matrix) {
        int m = matrix.size();
        if(m == 0)                  return 0;
        int n = matrix[0].size();
        vector<vector<int>> heights(m, vector<int>(n + 2, 0));              // 构建直方图矩阵,首尾各多加了个0作为哨兵
        for(int i = 0; i < m; i++) {
            for(int j = 1; j < n + 1; j++) {
                if(matrix[i][j - 1] == '1') {
                    heights[i][j] = (i == 0 ? 0 : heights[i - 1][j]) + 1;   // 按列统计连续的1的个数,个数情况作为直方图的高
                }
            }
        }

        int res = 0;
        for(int i = 0; i < m; i++) {                                        // 按行遍历直方图矩阵
            // 获取该行的直方图信息,计算可构成的最大矩阵面积。(算法同柱状图中的最大矩阵一样)
            int area = 0;
            stack<int> st;
            st.push(0);
            for(int j = 1; j < heights[i].size(); j++) {
                while(heights[i][st.top()] > heights[i][j]) {
                    int mid = st.top();             st.pop();
                    int w = j - st.top() - 1;
                    int h = heights[i][mid];
                    area = max(area, h * w);
                }
                st.push(j);
            }
            // 再计算不同行所构成的直方图中的最大矩阵面具
            res = max(res, area);
        }

        return res;
    }
};

Python

class Solution:
    def maximalRectangle(self, matrix: List[str]) -> int:
        m = len(matrix)
        if m == 0:
            return 0
        n = len(matrix[0])
        heights = [[0 for _ in range(n + 2)] for _ in range(m)]
        for i in range(m):
            for j in range(1, n + 1):
                if matrix[i][j - 1] == '1':
                    heights[i][j] = heights[i - 1][j] + 1 if i != 0 else 1
        
        res = 0
        for i in range(m):
            area = 0
            st = [0]
            for j in range(1, n + 2):
                while heights[i][st[-1]] > heights[i][j]:
                    mid = st[-1]
                    st.pop()
                    w = j - st[-1] - 1
                    h = heights[i][mid]
                    area = max(area, w * h)
                st.append(j)
            res = max(res, area)
        
        return res

参考视频:剑指offer040 矩阵中的最大矩形

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辰阳星宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值