Hard | LeetCode 85. 最大矩形 | 單調棧
阿新 • • 發佈:2021-07-11
85. 最大矩形
給定一個僅包含 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
示例 3:
輸入:matrix = [["0"]]
輸出:0
示例 4:
輸入:matrix = [["1"]]
輸出:1
示例 5:
輸入:matrix = [["0","0"]] 輸出:0
提示:
rows == matrix.length
cols == matrix[0].length
0 <= row, cols <= 200
matrix[i][j]
為'0'
或'1'
解題思路
此題和 Hard | LeetCode 84. 柱狀圖中最大的矩形 | 單調棧 實際上是一道題, 只不過從一維拓展到了二維上。
這道題首選要計算出每個位置(i, j)處從左往右連續的1的數量。那麼對於每一列。就成了下圖所示的樣子。
這樣這道題就轉化成了求柱狀圖中的最大的矩形。同樣參考LeetCode 84題的列舉邊界和單調棧的兩種思路。這道題很容易寫出答案。
方法一: 柱狀圖最大面積
public int maximalRectangle(char[][] matrix) { int m = matrix.length; if (m == 0) { return 0; } int n = matrix[0].length; // 新建一個二維陣列 int[][] left = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { // 計算matrix[i][j] 左側連續的數字1的數量 if (matrix[i][j] == '1') { left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1; } } } // 使用列舉邊界的方法, 求出柱形圖的最大面積 int ret = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (matrix[i][j] == '0') { continue; } // 計算以[i, j]為右下角的最大矩形, // 也就是說以當前的i作為起始邊界 int width = left[i][j]; int area = width; // 然後遍歷[0, i]的所有left值作為邊界 for (int k = i - 1; k >= 0; k--) { width = Math.min(width, left[k][j]); // 不斷更新面積的最大值 area = Math.max(area, (i - k + 1) * width); } ret = Math.max(ret, area); } } return ret; }
方法二: 單調棧
public int maximalRectangle(char[][] matrix) {
int m = matrix.length;
if (m == 0) {
return 0;
}
int n = matrix[0].length;
int[][] left = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == '1') {
left[i][j] = (j == 0 ? 0 : left[i][j - 1]) + 1;
}
}
}
int ret = 0;
// 對於每一列,使用基於柱狀圖的方法
for (int j = 0; j < n; j++) {
// 分別找出上面和下面的臨界點
int[] up = new int[m];
int[] down = new int[m];
Arrays.fill(down, m);
ArrayDeque<Integer> stack = new ArrayDeque<>();
for (int i = 0; i < m; i++) {
while (!stack.isEmpty() && left[stack.peek()][j] >= left[i][j]) {
down[stack.pop()] = i;
}
up[i] = stack.isEmpty() ? -1 : stack.peek();
stack.push(i);
}
for (int i = 0; i < m; i++) {
int height = down[i] - up[i] - 1;
int area = height * left[i][j];
ret = Math.max(ret, area);
}
}
return ret;
}