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))
优势 易于理解和实现 高效,通常用于解决此类问题 适用于某些特殊情况 空间优化 高效,适用于行数较多的情况
劣势 空间消耗较大 需要理解单调栈 较为复杂,不易实现 复杂度略高 需要位操作的理解和实现

应用示例

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


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

相关文章
|
11天前
|
算法
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
|
15天前
|
算法 数据可视化 数据挖掘
LeetCode题目104: 二叉树的最大深度(递归\迭代\层序遍历\尾递归优化\分治法实现 )
LeetCode题目104: 二叉树的最大深度(递归\迭代\层序遍历\尾递归优化\分治法实现 )
LeetCode题目104: 二叉树的最大深度(递归\迭代\层序遍历\尾递归优化\分治法实现 )
|
11天前
|
容器
【LeetCode刷题】栈和队列题目练习~
【LeetCode刷题】栈和队列题目练习~
【42页动态规划学习笔记分享】动态规划核心原理详解及27道LeetCode相关经典题目汇总(4)
【42页动态规划学习笔记分享】动态规划核心原理详解及27道LeetCode相关经典题目汇总
|
11天前
|
存储 算法
【42页动态规划学习笔记分享】动态规划核心原理详解及27道LeetCode相关经典题目汇总(1)
【42页动态规划学习笔记分享】动态规划核心原理详解及27道LeetCode相关经典题目汇总
|
11天前
|
算法
【经典LeetCode算法题目专栏分类】【第11期】递归问题:字母大小写全排列、括号生成
【经典LeetCode算法题目专栏分类】【第11期】递归问题:字母大小写全排列、括号生成
|
11天前
|
算法
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏
【经典LeetCode算法题目专栏分类】【第9期】深度优先搜索DFS与并查集:括号生成、岛屿问题、扫雷游戏
|
11天前
|
算法
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串
【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串
|
11天前
|
算法
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
【经典LeetCode算法题目专栏分类】【第7期】快慢指针与链表
|
11天前
|
算法
【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值
【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值