【队列&栈】LeetCode 85. 最大矩形【困难】
给定一个仅包含 0
和 1
、大小为 rows * cols
的二维二进制矩阵,找出只包含 1
的最大矩形,并返回其面积。
![](https://img2022.cnblogs.com/blog/1294992/202205/1294992-20220504104346984-1156842704.png)
输入:matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
输出:6
解释:最大矩形如上图所示。
示例 2:
输入:matrix = []
输出:0
示例 3:
输入:matrix = [["0"]]
输出:0
示例 4:
输入:matrix = [["1"]]
输出:1
示例 5:
输入:matrix = [["0","0"]]
输出:0
提示:
rows == matrix.length
cols == matrix[0].length
1 <= row, cols <= 200
matrix[i][j] 为 '0' 或 '1'
【分析:前缀和+单调栈】
参数定义:
m, n:矩阵行列数目。
pre:长度为n+1,初始值为0的数组,记录每个位置上方(包含当前位置)连续1的个数,最后一个位置为0,便于单调栈处理(不好理解的话参考下面绿色字体部分的详解即可)。
stack:单调栈,存储元素的索引,且索引对应的元素单调递增。
思路:
利用“前缀和”的思想求连续1的个数:
1. 对于pre的计算,当前位置j为0,则pre[j] = 0;当前位置为1,则需要加上上一层连续1的个数,即pre[j] += 1.
2. 如第二行(下标从0开始)pre[2] = [3,1,1,2,2,0],最后多一个0出来,是为了便于单调栈处理。
单调栈计算最大矩形:
1. 初始化栈,存入下标-1,便于处理所有元素弹出栈后的情况。
2. 当栈顶索引index对应的元素pre[index]大于当前索引为k的元素num时,将栈顶元素index弹出,因为栈中索引对应的值是单调递增的,所以此时栈顶元素stack[-1]到k-1之间的数均是不小于pre[index]的,此时以pre[index]为高的矩阵长度为k-stack[-1]-1,面积S=pre[index]*(k-stack[-1]-1)。
3. pre数组末尾添加0的目的,就是能将所有元素弹出栈,从而计算所有矩阵的面积。
4. 利用res记录最大矩阵面积。
时间复杂度:O(mn)
空间复杂度:O(n)
class Solution: def maximalRectangle(self, matrix: List[List[str]]) -> int: if not matrix: return 0 raws, cols = len(matrix), len(matrix[0]) # 记录当前位置上方连续“1”的个数 pre = [0] * (cols + 1) # pre:长度为n+1,初始值为0的数组,记录每个位置上方(包括当前位置)连续1的个数,最后一个位置为0,便于单调栈处理。 area = 0 # 初始化最大矩形面积 for raw in range(raws): for col in range(cols): # 前缀和 pre[col] = pre[col] + 1 if matrix[raw][col] == "1" else 0 # 单调栈 stack = [-1] # 初始化栈,存入下标-1,便于处理所有元素弹出栈后的情况 for cur_index, cur_num in enumerate(pre): while stack and pre[stack[-1]] > cur_num: top_index = stack.pop() area = max(area, pre[top_index] * (cur_index - stack[-1] - 1)) stack.append(cur_index) return area