栈
数组
动态规划
矩阵
单调栈
题目描述
给定一个仅包含 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.length
cols == matrix[0].length
1 <= row, cols <= 200
matrix[i][j]
为 '0'
或 '1'
解法
方法一:单调栈
我们把每一行视为柱状图的底部,对每一行求柱状图的最大面积即可。
时间复杂度 $O(m \times n)$,其中 $m$ 表示 $matrix$ 的行数,$n$ 表示 $matrix$ 的列数。
Python3 Java C++ Go Rust C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 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 ))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 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 ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 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 ;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75 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
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 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 ;
}
}