Hard
题目描述
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
示例 1:
输入: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"]]
输出:0
示例 3:
输入:matrix = [["1"]]
输出:1
提示:
rows == matrix.lengthcols == matrix[i].length1 <= rows, cols <= 200matrix[i][j]为'0'或'1'
解题思路
这道题可以转化为多个"柱状图中最大矩形"问题来解决。核心思路是将矩阵的每一行作为柱状图的底部,计算以该行为底的最大矩形面积。
解法思路:
预处理高度数组:对于每一行,计算以该行为底部时每一列的"柱子"高度。如果当前位置是'1’,高度为上一行该位置高度+1;如果是'0’,高度为0。
单调栈求最大矩形:对于每一行的高度数组,使用单调栈算法求出该柱状图中的最大矩形面积。这是经典的"柱状图中最大矩形"问题的解法。
优化处理:可以在遍历每一行时同时更新高度数组和计算最大面积,避免额外的空间开销。
算法步骤:
- 初始化高度数组,长度为列数
- 遍历矩阵每一行:
- 更新当前行的高度数组
- 使用单调栈计算当前柱状图的最大矩形面积
- 更新全局最大面积
单调栈的关键在于维护一个递增的栈,当遇到较小元素时弹出栈顶并计算以栈顶为高的矩形面积。
代码实现
class Solution {
public:
int maximalRectangle(vector<vector<char>>& matrix) {
if (matrix.empty() || matrix[0].empty()) return 0;
int rows = matrix.size(), cols = matrix[0].size();
vector<int> heights(cols, 0);
int maxArea = 0;
for (int i = 0; i < rows; i++) {
// 更新高度数组
for (int j = 0; j < cols; j++) {
heights[j] = (matrix[i][j] == '1') ? heights[j] + 1 : 0;
}
// 计算当前柱状图的最大矩形面积
maxArea = max(maxArea, largestRectangleArea(heights));
}
return maxArea;
}
private:
int largestRectangleArea(vector<int>& heights) {
stack<int> stk;
int maxArea = 0;
int n = heights.size();
for (int i = 0; i <= n; i++) {
int h = (i == n) ? 0 : heights[i];
while (!stk.empty() && heights[stk.top()] > h) {
int height = heights[stk.top()];
stk.pop();
int width = stk.empty() ? i : i - stk.top() - 1;
maxArea = max(maxArea, height * width);
}
stk.push(i);
}
return maxArea;
}
};
class Solution:
def maximalRectangle(self, matrix: List[List[str]]) -> int:
if not matrix or not matrix[0]:
return 0
rows, cols = len(matrix), len(matrix[0])
heights = [0] * cols
max_area = 0
for i in range(rows):
# 更新高度数组
for j in range(cols):
heights[j] = heights[j] + 1 if matrix[i][j] == '1' else 0
# 计算当前柱状图的最大矩形面积
max_area = max(max_area, self.largestRectangleArea(heights))
return max_area
def largestRectangleArea(self, heights):
stack = []
max_area = 0
n = len(heights)
for i in range(n + 1):
h = 0 if i == n else heights[i]
while stack and heights[stack[-1]] > h:
height = heights[stack.pop()]
width = i if not stack else i - stack[-1] - 1
max_area = max(max_area, height * width)
stack.append(i)
return max_area
public class Solution {
public int MaximalRectangle(char[][] matrix) {
if (matrix.Length == 0 || matrix[0].Length == 0) return 0;
int rows = matrix.Length, cols = matrix[0].Length;
int[] heights = new int[cols];
int maxArea = 0;
for (int i = 0; i < rows; i++) {
// 更新高度数组
for (int j = 0; j < cols; j++) {
heights[j] = (matrix[i][j] == '1') ? heights[j] + 1 : 0;
}
// 计算当前柱状图的最大矩形面积
maxArea = Math.Max(maxArea, LargestRectangleArea(heights));
}
return maxArea;
}
private int LargestRectangleArea(int[] heights) {
Stack<int> stack = new Stack<int>();
int maxArea = 0;
int n = heights.Length;
for (int i = 0; i <= n; i++) {
int h = (i == n) ? 0 : heights[i];
while (stack.Count > 0 && heights[stack.Peek()] > h) {
int height = heights[stack.Pop()];
int width = stack.Count == 0 ? i : i - stack.Peek() - 1;
maxArea = Math.Max(maxArea, height * width);
}
stack.Push(i);
}
return maxArea;
}
}
var maximalRectangle = function(matrix) {
if (!matrix || matrix.length === 0 || matrix[0].length === 0) return 0;
const rows = matrix.length;
const cols = matrix[0].length;
const heights = new Array(cols).fill(0);
let maxArea = 0;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
heights[j] = matrix[i][j] === '1' ? heights[j] + 1 : 0;
}
maxArea = Math.max(maxArea, largestRectangleInHistogram(heights));
}
return maxArea;
};
function largestRectangleInHistogram(heights) {
const stack = [];
let maxArea = 0;
for (let i = 0; i <= heights.length; i++) {
const h = i === heights.length ? 0 : heights[i];
while (stack.length > 0 && h < heights[stack[stack.length - 1]]) {
const height = heights[stack.pop()];
const width = stack.length === 0 ? i : i - stack[stack.length - 1] - 1;
maxArea = Math.max(maxArea, height * width);
}
stack.push(i);
}
return maxArea;
}
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(rows × cols),每个位置最多被压入和弹出栈一次 |
| 空间复杂度 | O(cols),需要高度数组和单调栈的空间 |