# [85. 最大矩形](https://leetcode.cn/problems/maximal-rectangle) [English Version](/solution/0000-0099/0085.Maximal%20Rectangle/README_EN.md) <!-- tags:栈,数组,动态规划,矩阵,单调栈 --> ## 题目描述 <!-- 这里写题目描述 --> <p>给定一个仅包含 <code>0</code> 和 <code>1</code> 、大小为 <code>rows x cols</code> 的二维二进制矩阵,找出只包含 <code>1</code> 的最大矩形,并返回其面积。</p> <p> </p> <p><strong>示例 1:</strong></p> <img alt="" src="https://fastly.jsdelivr.net/gh/doocs/leetcode@main/solution/0000-0099/0085.Maximal%20Rectangle/images/maximal.jpg" style="width: 402px; height: 322px;" /> <pre> <strong>输入:</strong>matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]] <strong>输出:</strong>6 <strong>解释:</strong>最大矩形如上图所示。 </pre> <p><strong>示例 2:</strong></p> <pre> <strong>输入:</strong>matrix = [["0"]] <strong>输出:</strong>0 </pre> <p><strong>示例 3:</strong></p> <pre> <strong>输入:</strong>matrix = [["1"]] <strong>输出:</strong>1 </pre> <p> </p> <p><strong>提示:</strong></p> <ul> <li><code>rows == matrix.length</code></li> <li><code>cols == matrix[0].length</code></li> <li><code>1 <= row, cols <= 200</code></li> <li><code>matrix[i][j]</code> 为 <code>'0'</code> 或 <code>'1'</code></li> </ul> ## 解法 ### 方法一:单调栈 我们把每一行视为柱状图的底部,对每一行求柱状图的最大面积即可。 时间复杂度 $O(m \times n)$,其中 $m$ 表示 $matrix$ 的行数,$n$ 表示 $matrix$ 的列数。 <!-- tabs:start --> ```python class Solution: def maximalRectangle(self, matrix: List[List[str]]) -> int: heights = [0] * len(matrix[0]) ans = 0 for row in matrix: for j, v in enumerate(row): if v == "1": heights[j] += 1 else: heights[j] = 0 ans = max(ans, self.largestRectangleArea(heights)) return ans def largestRectangleArea(self, heights: List[int]) -> int: n = len(heights) stk = [] left = [-1] * n right = [n] * n for i, h in enumerate(heights): while stk and heights[stk[-1]] >= h: stk.pop() if stk: left[i] = stk[-1] stk.append(i) stk = [] for i in range(n - 1, -1, -1): h = heights[i] while stk and heights[stk[-1]] >= h: stk.pop() if stk: right[i] = stk[-1] stk.append(i) return max(h * (right[i] - left[i] - 1) for i, h in enumerate(heights)) ``` ```java class Solution { public int maximalRectangle(char[][] matrix) { int n = matrix[0].length; int[] heights = new int[n]; int ans = 0; for (var row : matrix) { for (int j = 0; j < n; ++j) { if (row[j] == '1') { heights[j] += 1; } else { heights[j] = 0; } } ans = Math.max(ans, largestRectangleArea(heights)); } return ans; } private int largestRectangleArea(int[] heights) { int res = 0, n = heights.length; Deque<Integer> stk = new ArrayDeque<>(); int[] left = new int[n]; int[] right = new int[n]; Arrays.fill(right, n); for (int i = 0; i < n; ++i) { while (!stk.isEmpty() && heights[stk.peek()] >= heights[i]) { right[stk.pop()] = i; } left[i] = stk.isEmpty() ? -1 : stk.peek(); stk.push(i); } for (int i = 0; i < n; ++i) { res = Math.max(res, heights[i] * (right[i] - left[i] - 1)); } return res; } } ``` ```cpp class Solution { public: int maximalRectangle(vector<vector<char>>& matrix) { int n = matrix[0].size(); vector<int> heights(n); int ans = 0; for (auto& row : matrix) { for (int j = 0; j < n; ++j) { if (row[j] == '1') ++heights[j]; else heights[j] = 0; } ans = max(ans, largestRectangleArea(heights)); } return ans; } int largestRectangleArea(vector<int>& heights) { int res = 0, n = heights.size(); stack<int> stk; vector<int> left(n, -1); vector<int> right(n, n); for (int i = 0; i < n; ++i) { while (!stk.empty() && heights[stk.top()] >= heights[i]) { right[stk.top()] = i; stk.pop(); } if (!stk.empty()) left[i] = stk.top(); stk.push(i); } for (int i = 0; i < n; ++i) res = max(res, heights[i] * (right[i] - left[i] - 1)); return res; } }; ``` ```go func maximalRectangle(matrix [][]byte) int { n := len(matrix[0]) heights := make([]int, n) ans := 0 for _, row := range matrix { for j, v := range row { if v == '1' { heights[j]++ } else { heights[j] = 0 } } ans = max(ans, largestRectangleArea(heights)) } return ans } func largestRectangleArea(heights []int) int { res, n := 0, len(heights) var stk []int left, right := make([]int, n), make([]int, n) for i := range right { right[i] = n } for i, h := range heights { for len(stk) > 0 && heights[stk[len(stk)-1]] >= h { right[stk[len(stk)-1]] = i stk = stk[:len(stk)-1] } if len(stk) > 0 { left[i] = stk[len(stk)-1] } else { left[i] = -1 } stk = append(stk, i) } for i, h := range heights { res = max(res, h*(right[i]-left[i]-1)) } return res } ``` ```rust impl Solution { #[allow(dead_code)] pub fn maximal_rectangle(matrix: Vec<Vec<char>>) -> i32 { let n = matrix[0].len(); let mut heights = vec![0; n]; let mut ret = -1; for row in &matrix { Self::array_builder(row, &mut heights); ret = std::cmp::max(ret, Self::largest_rectangle_area(heights.clone())); } ret } /// Helper function, build the heights array according to the input #[allow(dead_code)] fn array_builder(input: &Vec<char>, heights: &mut Vec<i32>) { for (i, &c) in input.iter().enumerate() { heights[i] += match c { '1' => 1, '0' => { heights[i] = 0; 0 } _ => panic!("This is impossible"), }; } } /// Helper function, see: https://leetcode.com/problems/largest-rectangle-in-histogram/ for details #[allow(dead_code)] fn largest_rectangle_area(heights: Vec<i32>) -> i32 { let n = heights.len(); let mut left = vec![-1; n]; let mut right = vec![-1; n]; let mut stack: Vec<(usize, i32)> = Vec::new(); let mut ret = -1; // Build left vector for (i, h) in heights.iter().enumerate() { while !stack.is_empty() && stack.last().unwrap().1 >= *h { stack.pop(); } if stack.is_empty() { left[i] = -1; } else { left[i] = stack.last().unwrap().0 as i32; } stack.push((i, *h)); } stack.clear(); // Build right vector for (i, h) in heights.iter().enumerate().rev() { while !stack.is_empty() && stack.last().unwrap().1 >= *h { stack.pop(); } if stack.is_empty() { right[i] = n as i32; } else { right[i] = stack.last().unwrap().0 as i32; } stack.push((i, *h)); } // Calculate the max area for (i, h) in heights.iter().enumerate() { ret = std::cmp::max(ret, (right[i] - left[i] - 1) * *h); } ret } } ``` ```cs using System; using System.Collections.Generic; using System.Linq; public class Solution { private int MaximalRectangleHistagram(int[] height) { var stack = new Stack<int>(); var result = 0; var i = 0; while (i < height.Length || stack.Any()) { if (!stack.Any() || (i < height.Length && height[stack.Peek()] < height[i])) { stack.Push(i); ++i; } else { var previousIndex = stack.Pop(); var area = height[previousIndex] * (stack.Any() ? (i - stack.Peek() - 1) : i); result = Math.Max(result, area); } } return result; } public int MaximalRectangle(char[][] matrix) { var lenI = matrix.Length; var lenJ = lenI == 0 ? 0 : matrix[0].Length; var height = new int[lenJ]; var result = 0; for (var i = 0; i < lenI; ++i) { for (var j = 0; j < lenJ; ++j) { if (matrix[i][j] == '1') { ++height[j]; } else { height[j] = 0; } } result = Math.Max(result, MaximalRectangleHistagram(height)); } return result; } } ``` <!-- tabs:end --> <!-- end -->