Given a binary matrix mat[][] of size n x m, find the maximum area of a rectangle containing only 1s. You are allowed to swap any columns of the matrix any number of times before forming the rectangle. Return the maximum possible rectangle area.
[Naive Approach] Sort Heights Row-wise - O(n * m * log m) Time and O(n * m) Space
The idea is to use an auxiliary matrix to store count of consecutive 1's in every column. Once we have these counts, we sort all rows of auxiliary matrix in non-increasing order of counts. Finally traverse the sorted rows to find the maximum area.Â
Let us understand with the following example.
Step 1: First of all, calculate no. of consecutive 1's in every column. An auxiliary array height[][] is used to store the counts of consecutive 1's.
Step 2: Sort the rows in non-increasing fashion. After sorting step the matrix height[][] would beÂ
The sorting is actually the swapping of columns so that the column with the highest possible rectangle is placed first, after that comes the column that allows the second highest rectangle and so on. So, in the example there are 2 columns that can form a rectangle of height 3. That makes an area of 3*2 = 6. If we try to make the rectangle wider the height drops to 1, because there are no columns left that allow a higher rectangle on the 3rd row.
Step 3: Traverse each row of height[][] and check for the max area. Since every row is sorted by count of 1's, current area can be calculated by multiplying column number with value in height[i][j].
C++
#include<iostream>#include<vector>#include<algorithm>usingnamespacestd;intmaxArea(vector<vector<int>>&mat){intn=mat.size();intm=mat[0].size();vector<vector<int>>height(n,vector<int>(m,0));// Build height matrix.for(intj=0;j<m;j++){height[0][j]=mat[0][j];for(inti=1;i<n;i++){if(mat[i][j]==1){height[i][j]=height[i-1][j]+1;}}}intans=0;for(inti=0;i<n;i++){vector<int>row=height[i];// Sort heights because columns can be rearranged.sort(row.rbegin(),row.rend());for(intj=0;j<m;j++){ans=max(ans,row[j]*(j+1));}}returnans;}intmain(){vector<vector<int>>mat={{0,1,0,1,0},{0,1,0,1,1},{1,1,0,1,0}};cout<<maxArea(mat)<<endl;mat={{0,1,0,1,0},{0,1,1,1,1},{1,1,1,0,1},{1,1,1,1,1}};cout<<maxArea(mat)<<endl;return0;}
Java
importjava.util.Collections;importjava.util.Arrays;classGFG{staticintmaxArea(int[][]mat){intn=mat.length;intm=mat[0].length;int[][]height=newint[n][m];// Build height matrix.for(intj=0;j<m;j++){height[0][j]=mat[0][j];for(inti=1;i<n;i++){if(mat[i][j]==1){height[i][j]=height[i-1][j]+1;}}}intans=0;for(inti=0;i<n;i++){Integer[]row=newInteger[m];for(intj=0;j<m;j++){row[j]=height[i][j];}// Sort heights because columns can be rearranged.Arrays.sort(row,Collections.reverseOrder());for(intj=0;j<m;j++){ans=Math.max(ans,row[j]*(j+1));}}returnans;}publicstaticvoidmain(String[]args){int[][]mat={{0,1,0,1,0},{0,1,0,1,1},{1,1,0,1,0}};System.out.println(maxArea(mat));mat=newint[][]{{0,1,0,1,0},{0,1,1,1,1},{1,1,1,0,1},{1,1,1,1,1}};System.out.println(maxArea(mat));}}
Python
defmaxArea(mat):n=len(mat)m=len(mat[0])height=[[0]*mfor_inrange(n)]# Build height matrix.forjinrange(m):height[0][j]=mat[0][j]foriinrange(1,n):ifmat[i][j]==1:height[i][j]=height[i-1][j]+1ans=0foriinrange(n):row=height[i][:]# Sort heights because columns can be rearranged.row.sort(reverse=True)forjinrange(m):ans=max(ans,row[j]*(j+1))returnansif__name__=="__main__":mat=[[0,1,0,1,0],[0,1,0,1,1],[1,1,0,1,0]]print(maxArea(mat))mat=[[0,1,0,1,0],[0,1,1,1,1],[1,1,1,0,1],[1,1,1,1,1]]print(maxArea(mat))
C#
usingSystem;usingSystem.Linq;classGFG{staticintmaxArea(int[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);int[,]height=newint[n,m];// Build height matrix.for(intj=0;j<m;j++){height[0,j]=mat[0,j];for(inti=1;i<n;i++){if(mat[i,j]==1){height[i,j]=height[i-1,j]+1;}}}intans=0;for(inti=0;i<n;i++){int[]row=newint[m];for(intj=0;j<m;j++){row[j]=height[i,j];}// Sort heights because columns can be rearranged.Array.Sort(row);Array.Reverse(row);for(intj=0;j<m;j++){ans=Math.Max(ans,row[j]*(j+1));}}returnans;}staticvoidMain(){int[,]mat={{0,1,0,1,0},{0,1,0,1,1},{1,1,0,1,0}};Console.WriteLine(maxArea(mat));mat=newint[,]{{0,1,0,1,0},{0,1,1,1,1},{1,1,1,0,1},{1,1,1,1,1}};Console.WriteLine(maxArea(mat));}}
JavaScript
functionmaxArea(mat){constn=mat.length;constm=mat[0].length;constheight=Array.from({length:n},()=>newArray(m).fill(0));// Build height matrix.for(letj=0;j<m;j++){height[0][j]=mat[0][j];for(leti=1;i<n;i++){if(mat[i][j]===1){height[i][j]=height[i-1][j]+1;}}}letans=0;for(leti=0;i<n;i++){constrow=[...height[i]];// Sort heights because columns can be rearranged.row.sort((a,b)=>b-a);for(letj=0;j<m;j++){ans=Math.max(ans,row[j]*(j+1));}}returnans;}// Driver Codeletmat=[[0,1,0,1,0],[0,1,0,1,1],[1,1,0,1,0]];console.log(maxArea(mat));mat=[[0,1,0,1,0],[0,1,1,1,1],[1,1,1,0,1],[1,1,1,1,1]];console.log(maxArea(mat));
Output
6
9
[Expected Approach] Counting Sort on Heights - O(n * (n + m)) Time and O(n * m) Space
The idea is to avoid using comparison sort. Since height values can only range from 0 to n, we count the frequency of each height and rebuild the row in decreasing order using counting sort. Then we calculate the maximum rectangle area for each row.
C++
#include<iostream>#include<vector>usingnamespacestd;intmaxArea(vector<vector<int>>&mat){intn=mat.size();intm=mat[0].size();vector<vector<int>>height(n,vector<int>(m,0));// height[i][j] stores consecutive 1s ending at row i in column j.for(intj=0;j<m;j++){height[0][j]=mat[0][j];for(inti=1;i<n;i++){if(mat[i][j]==1){height[i][j]=height[i-1][j]+1;}}}intans=0;for(inti=0;i<n;i++){vector<int>count(n+1,0);// Count frequency of each height.for(intj=0;j<m;j++){count[height[i][j]]++;}intcol=0;// Rearrange heights in decreasing order using counting sort.for(inth=n;h>=0;h--){while(count[h]>0){height[i][col]=h;col++;count[h]--;}}// Calculate maximum area for this row.for(intj=0;j<m;j++){ans=max(ans,height[i][j]*(j+1));}}returnans;}intmain(){vector<vector<int>>mat={{0,1,0,1,0},{0,1,0,1,1},{1,1,0,1,0}};cout<<maxArea(mat)<<endl;mat={{0,1,0,1,0},{0,1,1,1,1},{1,1,1,0,1},{1,1,1,1,1}};cout<<maxArea(mat)<<endl;return0;}
Java
classGFG{staticintmaxArea(int[][]mat){intn=mat.length;intm=mat[0].length;int[][]height=newint[n][m];// height[i][j] stores consecutive 1s ending at row i in column j.for(intj=0;j<m;j++){height[0][j]=mat[0][j];for(inti=1;i<n;i++){if(mat[i][j]==1){height[i][j]=height[i-1][j]+1;}}}intans=0;for(inti=0;i<n;i++){int[]count=newint[n+1];// Count frequency of each height.for(intj=0;j<m;j++){count[height[i][j]]++;}intcol=0;// Rearrange heights in decreasing order using counting sort.for(inth=n;h>=0;h--){while(count[h]>0){height[i][col]=h;col++;count[h]--;}}// Calculate maximum area for this row.for(intj=0;j<m;j++){ans=Math.max(ans,height[i][j]*(j+1));}}returnans;}publicstaticvoidmain(String[]args){int[][]mat={{0,1,0,1,0},{0,1,0,1,1},{1,1,0,1,0}};System.out.println(maxArea(mat));mat=newint[][]{{0,1,0,1,0},{0,1,1,1,1},{1,1,1,0,1},{1,1,1,1,1}};System.out.println(maxArea(mat));}}
Python
defmaxArea(mat):n=len(mat)m=len(mat[0])height=[[0]*mfor_inrange(n)]# height[i][j] stores consecutive 1s ending at row i in column j.forjinrange(m):height[0][j]=mat[0][j]foriinrange(1,n):ifmat[i][j]==1:height[i][j]=height[i-1][j]+1ans=0foriinrange(n):count=[0]*(n+1)# Count frequency of each height.forjinrange(m):count[height[i][j]]+=1col=0# Rearrange heights in decreasing order using counting sort.forhinrange(n,-1,-1):whilecount[h]>0:height[i][col]=hcol+=1count[h]-=1# Calculate maximum area for this row.forjinrange(m):ans=max(ans,height[i][j]*(j+1))returnansif__name__=="__main__":mat=[[0,1,0,1,0],[0,1,0,1,1],[1,1,0,1,0]]print(maxArea(mat))mat=[[0,1,0,1,0],[0,1,1,1,1],[1,1,1,0,1],[1,1,1,1,1]]print(maxArea(mat))
C#
usingSystem;classGFG{staticintmaxArea(int[,]mat){intn=mat.GetLength(0);intm=mat.GetLength(1);int[,]height=newint[n,m];// height[i, j] stores consecutive 1s ending at row i in column j.for(intj=0;j<m;j++){height[0,j]=mat[0,j];for(inti=1;i<n;i++){if(mat[i,j]==1){height[i,j]=height[i-1,j]+1;}}}intans=0;for(inti=0;i<n;i++){int[]count=newint[n+1];// Count frequency of each height.for(intj=0;j<m;j++){count[height[i,j]]++;}intcol=0;// Rearrange heights in decreasing order using counting sort.for(inth=n;h>=0;h--){while(count[h]>0){height[i,col]=h;col++;count[h]--;}}// Calculate maximum area for this row.for(intj=0;j<m;j++){ans=Math.Max(ans,height[i,j]*(j+1));}}returnans;}staticvoidMain(){int[,]mat={{0,1,0,1,0},{0,1,0,1,1},{1,1,0,1,0}};Console.WriteLine(maxArea(mat));mat=newint[,]{{0,1,0,1,0},{0,1,1,1,1},{1,1,1,0,1},{1,1,1,1,1}};Console.WriteLine(maxArea(mat));}}
JavaScript
functionmaxArea(mat){constn=mat.length;constm=mat[0].length;constheight=Array.from({length:n},()=>newArray(m).fill(0));// height[i][j] stores consecutive 1s ending at row i in column j.for(letj=0;j<m;j++){height[0][j]=mat[0][j];for(leti=1;i<n;i++){if(mat[i][j]===1){height[i][j]=height[i-1][j]+1;}}}letans=0;for(leti=0;i<n;i++){constcount=newArray(n+1).fill(0);// Count frequency of each height.for(letj=0;j<m;j++){count[height[i][j]]++;}letcol=0;// Rearrange heights in decreasing order using counting sort.for(leth=n;h>=0;h--){while(count[h]>0){height[i][col]=h;col++;count[h]--;}}// Calculate maximum area for this row.for(letj=0;j<m;j++){ans=Math.max(ans,height[i][j]*(j+1));}}returnans;}// Driver Codeletmat=[[0,1,0,1,0],[0,1,0,1,1],[1,1,0,1,0]];console.log(maxArea(mat));mat=[[0,1,0,1,0],[0,1,1,1,1],[1,1,1,0,1],[1,1,1,1,1]];console.log(maxArea(mat));