当前位置: 首页 > article >正文

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

题目描述

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

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

文章目录

  • 题目描述
  • 解法一:暴力解法
    • 思路
    • 解题方法
    • 复杂度
    • Code
  • 解法二:单调栈解法
    • 思路
    • 解题方法
    • 复杂度
    • Code

解法一:暴力解法

思路

首先, 按行获取到达某一元素位置时,之前与当前连续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 矩阵中的最大矩形


http://www.kler.cn/a/14572.html

相关文章:

  • 基于springboot“漫画之家”系统(附源码、设计文档)
  • K8S第一讲 Kubernetes之Secret详解
  • ansible自动运维——ansible使用临时命令通过模块来执行任务
  • Spring Boot中使用Redis
  • Cloud Kernel SIG月度动态:发布 Anolis 8.8 镜像、kABI 社区共建流程
  • 代码随想录_贪心_leetcode 1005 134
  • 数学知识四
  • 注册服务 linux
  • 开放原子训练营第三期:RT-Thread 学习有感
  • Netty 单机百万连接测试
  • 聚焦能源 | 赛宁网安亮相2023年中国能源网络安全大会
  • 4.26日报
  • OpenCL、CUDA 与C++ AMP之间,开发者该如何选择
  • NGFW的protal认证实验
  • 【翻译一下官方文档】认识uniCloud云数据库(基础篇)
  • 部署Ansible
  • 容易忽视的细节:Log4j 配置导致的零点接口严重超时
  • 常用的设计模式(单例模式、工厂模式等)
  • 最短路径Floyd与区间DP
  • chatgpt接入ROS2控制小海龟