动态规划 
      
    
      
      
      
        单调栈 
      
    
      
      
      
        数组 
      
    
      
      
      
        栈 
      
    
      
      
      
        矩阵 
      
    
   
  
    
      
       
     
  
  
    
      
    
    
      
       
     
  
题目描述 
给定一个仅包含 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 <= rows, 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 ; 
     } 
}