LeetCode 题目 85:最大矩形

简介: LeetCode 题目 85:最大矩形

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。

会一些的技术:数据分析、算法、SQL、大数据相关、python

欢迎加入社区:码上找工作

作者专栏每日更新:

LeetCode解锁1000题: 打怪升级之旅

python数据分析可视化:企业实战案例

python源码解读

程序员必备的数学知识与应用

备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

题目描述

给定一个仅包含 01 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

输入格式
  • matrix:二维字符数组,其中 ‘1’ 和 ‘0’ 分别表示有和无。
输出格式
  • 返回最大矩形的面积。

示例

示例 1
输入: 
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
输出: 6

方法一:动态规划 - 按行计算高度

解题步骤
  1. 构建高度数组:将每一行视为底,构建当前行为底的直方图。
  2. 直方图最大矩形:使用单调栈找出每个直方图的最大矩形面积。
完整的规范代码
def maximalRectangle(matrix):
    """
    动态规划计算基于直方图的最大矩形面积
    :param matrix: List[List[str]], 二维二进制矩阵
    :return: int, 最大矩形的面积
    """
    if not matrix or not matrix[0]:
        return 0
    
    max_area = 0
    n = len(matrix[0])
    height = [0] * (n + 1)  # 额外的一个0作为哨兵,简化代码
    
    for row in matrix:
        for i in range(n):
            height[i] = height[i] + 1 if row[i] == '1' else 0
        
        # 单调栈计算最大矩形面积
        stack = []
        for i in range(n + 1):
            while stack and height[i] < height[stack[-1]]:
                h = height[stack.pop()]
                w = i if not stack else i - stack[-1] - 1
                max_area = max(max_area, h * w)
            stack.append(i)
    
    return max_area
# 示例调用
print(maximalRectangle([["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","1","1"], ["1","0","0","1","0"]]))  # 输出: 6
算法分析
  • 时间复杂度:(O(M * N)),其中 (M) 和 (N) 分别是矩阵的行数和列数。
  • 空间复杂度:(O(N)),用于存储高度数组和栈的空间。

方法二:动态规划 - 优化的行处理

解题步骤
  1. 计算三个数组leftrightheight数组。
  • left[i] 表示第 i 列的连续 1 最左能达到的边界。
  • right[i] 表示第 i 列的连续 1 最右能达到的边界。
  • height[i] 表示第 i 列的连续 1 的高度。
  1. 更新和计算面积:在更新这三个数组的同时,计算可能的最大矩形面积。
完整的规范代码
def maximalRectangle(matrix):
    """
    动态规划优化的行处理计算最大矩形面积
    :param matrix: List[List[str]], 二维二进制矩阵
    :return: int, 最大矩形的面积
    """
    if not matrix or not matrix[0]:
        return 0
    
    max_area = 0
    n = len(matrix[0])
    height = [0] * n
    left = [0] * n
    right = [n] * n
    for row in matrix:
        cur_left, cur_right = 0, n
        
        # 更新左边界
        for i in range(n):
            if row[i] == '1':
                left[i] = max(left[i], cur_left)
            else:
                left[i] = 0
                cur_left = i + 1
        
        # 更新右边界
        for i in range(n-1, -1, -1):
            if row[i] == '1':
                right[i] = min(right[i], cur_right)
            else:
                right[i] = n
                cur_right = i
        
        # 更新高度和计算面积
        for i in range(n):
            if row[i] == '1':
                height[i] += 1
                max_area = max(max_area, (right[i] - left[i]) * height[i])
            else:
                height[i] = 0
    
    return max_area
# 示例调用
print(maximalRectangle([["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","1","1"], ["1","0","0","1","0"]]))  # 输出: 6
算法分析
  • 时间复杂度:(O(M * N)),每个元素处理一次。
  • 空间复杂度:(O(N)),用于存储 leftrightheight 数组。

方法三:最大矩形转化为最大直方图问题

解题步骤
  1. 转化问题:将每一行看作直方图的底部,通过累积将二维问题转换为一系列一维直方图问题。
  2. 应用单调栈:对每个生成的直方图使用单调栈方法计算最大矩形面积。
完整的规范代码
def maximalRectangle(matrix):
    """
    转化为直方图处理每行的最大矩形面积
    :param matrix: List[List[str]], 二维二进制矩阵
    :return: int, 最大矩形的面积
    """
    if not matrix:
        return 0
    max_area = 0
    n = len(matrix[0])
    height = [0] * (n + 1)
    for row in matrix:
        for i in range(n):
            height[i] = height[i] + 1 if row[i] == '1' else 0
        stack = [-1]
        for i in range(n + 1):
            while height[i] < height[stack[-1]]:
                h = height[stack.pop()]
                w = i - stack[-1] - 1
                max_area = max(max_area, h * w)
            stack.append(i)
    return max_area
# 示例调用
print(maximalRectangle([["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","1","1"], ["1","0","0","1","0"]]))  # 输出: 6
算法分析
  • 时间复杂度:(O(M * N)),其中 (M) 和 (N) 分别是矩阵的行数和列数。每个元素最多进出栈一次。
  • 空间复杂度:(O(N)),用于存储高度和栈的空间。

方法四:改进的动态规划

解题步骤
  1. 建立模型:类似于方法二,使用动态规划,但这次只用两个数组交替更新,减少空间复杂度。
  2. 连续更新:使用两个数组 current_leftcurrent_right 交替更新,以优化空间使用。
完整的规范代码
def maximalRectangle(matrix):
    """
    改进的动态规划算法,优化空间复杂度
    :param matrix: List[List[str]], 二维二进制矩阵
    :return: int, 最大矩形的面积
    """
    if not matrix or not matrix[0]:
        return 0
    max_area = 0
    n = len(matrix[0])
    height = [0] * n
    current_left = [0] * n
    current_right = [n] * n
    for row in matrix:
        left, right = 0, n
        
        # 更新左边界
        for i in range(n):
            if row[i] == '1':
                current_left[i] = max(current_left[i], left)
            else:
                current_left[i] = 0
                left = i + 1
        
        # 更新右边界
        for i in range(n - 1, -1, -1):
            if row[i] == '1':
                current_right[i] = min(current_right[i], right)
            else:
                current_right[i] = n
                right = i
        
        # 更新高度和计算面积
        for i in range(n):
            if row[i] == '1':
                height[i] += 1
                max_area = max(max_area, (current_right[i] - current_left[i]) * height[i])
            else:
                height[i] = 0
    return max_area
# 示例调用
print(maximalRectangle([["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","1","1"], ["1","0","0","1","0"]]))  # 输出: 6
算法分析
  • 时间复杂度:(O(M * N)),每个元素被处理一次。
  • 空间复杂度:(O(N)),使用了三个数组来存储当前行的状态。

方法五:基于位操作的优化

解题步骤
  1. 位操作:将每一行看作一个二进制数,通过位操作合并行,求连续行的公共 ‘1’ 部分。
  2. 求连续最大行数:计算每一列连续 ‘1’ 的最大数量,进而计算最大面积。
完整的规范代码
def maximalRectangle(matrix):
    """
    基于位操作的优化算法,处理连续行的公共部分
    :param matrix: List[List[str]], 二维二进制矩阵
    :return: int, 最大矩形的面积
    """
    if not matrix:
        return 0
    m, n = len(matrix), len(matrix[0])
    heights = [0] * n
    max_area = 0
    for i in range(m):
        for j in range(n):
            # 更新高度
            if matrix[i][j] == '1':
                heights[j] += 1
            else:
                heights[j] = 0
        
        # 使用单调栈找最大矩形面积
        stack = [-1]
        for j in range(n + 1):
            while stack and (j == n or heights[stack[-1]] > heights[j]):
                h = heights[stack.pop()]
                w = j if stack[-1] == -1 else j - stack[-1] - 1
                max_area = max(max_area, h * w)
            stack.append(j)
    return max_area
# 示例调用
print(maximalRectangle([["1","0","1","0","0"], ["1","0","1","1","1"], ["1","1","1","1","1"], ["1","0","0","1","0"]]))  # 输出: 6
算法分析
  • 时间复杂度:(O(M * N)),每行使用单调栈算法处理。
  • 空间复杂度:(O(N)),使用栈和高度数组存储信息。

不同算法的优劣势对比

特征 方法一:动态规划 方法二:单调栈 方法三:分治法 方法四:改进动态规划 方法五:位操作优化
时间复杂度 (O(M * N)) (O(M * N)) 平均 (O(M * N)), 最坏 (O(M * N^2)) (O(M * N)) (O(M * N))
空间复杂度 (O(N)) (O(N)) (O(N)) (O(N)) (O(N))
优势 易于理解和实现 高效,通常用于解决此类问题 适用于某些特殊情况 空间优化 高效,适用于行数较多的情况
劣势 空间消耗较大 需要理解单调栈 较为复杂,不易实现 复杂度略高 需要位操作的理解和实现

应用示例

这些方法在计算几何、图形渲染、图像处理、资源分配和数据分析中非常有用,特别是在需要优化和处理大规模数据集的情况下。


欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
2月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
|
3月前
|
SQL Oracle 关系型数据库
CASE WHEN 语句的语法及示例,LeetCode 题目 “确认率” 练习
本文介绍了SQL中CASE语句的两种形式和语法,并通过LeetCode题目“确认率”的SQL查询示例展示了CASE语句在实际问题中的应用,解释了如何使用CASE语句计算特定条件的比率。
|
4月前
|
算法
LeetCode第12题目整数转罗马数字
该文章介绍了 LeetCode 第 12 题整数转罗马数字的解法,通过使用 TreeMap 按照整数从大到小排序,先使用大的罗马数字表示整数,再用小的,核心是先表示完大的罗马数字,想通此点该题较简单。
LeetCode第12题目整数转罗马数字
|
4月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
57 6
|
4月前
|
算法
LeetCode第13题目罗马数字转整数
该文章介绍了 LeetCode 第 13 题罗马数字转整数的解法,通过从大到小解析罗马数字,根据罗马数字的特点,按照从大到小的顺序匹配罗马数字和整数的关系,从而解决该问题,同时强调要注意观察题目考查的知识点特征。
|
6月前
|
C语言
详解Leetcode中关于malloc模拟开辟二维数组问题,涉及二维数组的题目所给函数中的各个参数的解读
详解Leetcode中关于malloc模拟开辟二维数组问题,涉及二维数组的题目所给函数中的各个参数的解读
40 1
|
6月前
|
算法
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
|
5月前
|
存储 算法
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
经典的滑动窗口的题目 力扣 2799. 统计完全子数组的数目(面试题)
|
6月前
|
容器
【LeetCode刷题】栈和队列题目练习~
【LeetCode刷题】栈和队列题目练习~