There is a problem to find the maximum area of the 1 in the 0-1 matrix. In this problem there are two cases:
area to be measure is of shape square. that\'s
The problem can be reduced to finding the maximum rectangle area in a histogram, multiple times.
After each row, you calculate the histogram built until that row, and that calculate the maximum area rectangle in that histogram.
int maximalRectangle(vector<vector<char> > &mat) {
int rows=mat.size();
if(rows==0)return 0;
int columns = mat[0].size();
int temp[columns];
for(int i=0;i<columns;i++){
temp[i] = mat[0][i]-'0';
}
int maxArea=0;
maxArea = max(maxArea,maxUtil(temp,columns));
// cout<<"before loop\n";
// print1d(temp,columns);
for(int i=1;i<rows;i++){
for(int j=0;j<columns;j++){
temp[j] = (mat[i][j]-'0')?temp[j]+1:0;
}
// cout<<"after iteration : "<<i<<endl;
// print1d(temp,columns);
maxArea = max(maxArea,maxUtil(temp,columns));
// cout<<"maxarea = "<<maxArea<<endl;
}
return maxArea;
}
temp is the histogram in each step and maxutil calculates the max rectanglular area in that histogram.
I would try the following:
(1) Decompose the matrix into connected components (through BFS).
(2) For each connected component, look for the maximal rectangle.
To do (2), I would first look for vertical rectangles: Find the maximal possible width for each consecutive (min_y, max_y), and therefore the area (iteratively, in O(1) per row, just by looking at the min/max of 1's in that row of the connected component). Then I would transpose the matrix, and repeat the process.
The total running time is O(MxN) for BFS, then O(width^2 + height^2) for each connected componenet, for a total of O(MXN + M^2 + N^2).
I wonder what's the asymptotically optimal solution though.
**
//use this dynamic programming approach
//The problem can be reduced to finding the maximum rectangle area in a histogram, multiple times.
After each row, you calculate the histogram built until that row, and that calculate the maximum area rectangle in that histogram.
**
import java.util.Scanner;
public class LargestRectInAmatrix {
static int row,col,matrix[][];
static int maxArea=0;
static int barMatrix[];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
row=sc.nextInt();
col=sc.nextInt();
matrix=new int[row][col];
barMatrix=new int[col];
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
matrix[i][j]=sc.nextInt();
}
}
startSolution();
System.out.println(maxArea);
}
private static void startSolution()
{
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
if(matrix[i][j]==0)
{
barMatrix[j]=0;
}
else
barMatrix[j]=barMatrix[j]+matrix[i][j];
}
int area=calculateArea(0,col-1);
if(area>maxArea)
{
maxArea=area;
}
}
}
private static int calculateArea(int l,int h)
{
if(l>h)
{
return Integer.MIN_VALUE;
}
if(l==h)
{
return barMatrix[l];
}
int u=calMinimumIndex(l,h);
return (max(calculateArea(l, u-1),calculateArea(u+1, h),barMatrix[u]*(h-l+1)));
}
private static int max(int a,int b,int c)
{
if(a>b)
{
if(a>c)
{
return a;
}
else
return c;
}
else
if(b>c)
{
return b;
}
else
return c;
}
private static int calMinimumIndex(int l,int h)
{
int min=Integer.MAX_VALUE;
int min_index=0;
for(int i=l;l<=h;i++)
{
if(barMatrix[i]<min){
min=barMatrix[i];
min_index=i;
}
}
return min_index;
}
}
Another simpler approach is to use two temp M x N arrays to compute the length of rectangles (row and column wise) - ie count of consecutive 1's then. Traverse the two temp matrices to find max repeating lengths (row and column wise).
Here is the code for the same.
int GetMaxRectangularArea(vector<vector<int>> & matrix, int nRows, int nCols)
{
vector<vector<int>> rowLengths(nRows, vector<int>(nCols));
vector<vector<int>> colLengths(nRows, vector<int>(nCols));
// initialize first column of rowLengths with first column of matrix
for (int i = 0; i < nRows; i++) {
rowLengths[i][0] = matrix[i][0];
}
// initialize first row of colLengths with first row of matrix
for (int j = 0; j < nCols; j++) {
colLengths[0][j] = matrix[0][j];
}
// Compute row wise length of consecutive 1's in rowLengths
for (int i = 0; i < nRows; i++) {
for (int j = 1; j < nCols; j++) {
if (matrix[i][j] == 1) {
rowLengths[i][j] = 1 + rowLengths[i][j - 1];
}
else {
rowLengths[i][j] = 0;
}
}
}
// Compute column wise length of consecutive 1's in colLengths
for (int j = 0; j < nCols; j++) {
for (int i = 1; i < nRows; i++) {
if (matrix[i][j] == 1) {
colLengths[i][j] = 1 + colLengths[i- 1][j];
}
else {
colLengths[i][j] = 0;
}
}
}
// Now traverse the rowLengths array to find max length sub array
int maxArea = 0;
for (int j = nCols - 1; j >= 0; j--) {
int currentArea = 0;
int currentMax = -1;
int repeats = 1;
for (int i = nRows - 1; i >= 0; i--) {
if (rowLengths[i][j] != currentMax) {
if (currentMax != -1) {
currentArea = currentMax * repeats;
if (currentArea > maxArea) {
maxArea = currentArea;
}
}
currentMax = rowLengths[i][j];
repeats = 1;
}
else {
repeats++;
}
}
currentArea = currentMax * repeats;
if (currentArea > maxArea) {
maxArea = currentArea;
}
}
for (int i = nRows - 1; i >= 0; i--) {
int currentArea = 0;
int currentMax = -1;
int repeats = 1;
for (int j = nCols - 1; j >= 0; j--) {
if (colLengths[i][j] != currentMax) {
if (currentMax != -1) {
currentArea = currentMax * repeats;
if (currentArea > maxArea) {
maxArea = currentArea;
}
}
currentMax = colLengths[i][j];
repeats = 1;
}
else {
repeats++;
}
}
currentArea = currentMax * repeats;
if (currentArea > maxArea) {
maxArea = currentArea;
}
}
return maxArea;
}
class GfG{
public int maxArea(int a[][],int m,int n){
if(a==null || m==0 || n== 0) return 0;
m = a.length;
n = a[0].length;
int dp[] = new int[n+1];
int height[] = new int[n];
int p = 0;
dp[p] = -1;
int ans = 0;
//System.out.println("1 ");
for(int i = 0;i<m;i++){
for(int j = 0;j<n;j++){
if(a[i][j]==1){
height[j] += a[i][j];
}
else{
height[j] = 0;
}
}
p= 0;
//System.out.println("2 ");
for(int j = 0;j<n;j++){
while(p>0 && height[j] < height[dp[p]]){
int start = dp[p-1];
ans = Math.max(ans,(j-start-1)*height[dp[p]]);
p--;
//System.out.println("1 ");
}
dp[++p] = j;
}
}
return ans;
}
}
I'll step through a few solutions of increasing difficulty / decreasing runtime complexity.
First, a brute force solution. Generate every possible rectangle. You can do this by iterating through every pair of points (r1,c1) (r2,c2) with r1 ≤ r2 and c1 ≤ c2 (can be done with 4 for loops). If a rectangle does not contain a 0, you compare the area to the largest area found so far. This is an O(R^3C^3).
We can speed up the valid rectangle check to O(1). We do this by doing a DP where dp(r, c) stores the number of 0's in the rectangle ((1, 1), (r, c)).
Then the number of 0's in ((r1, c1), (r2, c2)) is
You can then check if a rectangle is valid by nzeroes(r1,c1,r2,c2) == 0.
There is an O(R^2C) solution for this using a simple DP and a stack. The DP works per column, by finding the number of 1 cells above a cell until the next 0. The dp is as follows:
You then do the following:
area = 0
for each row r:
stack = {}
stack.push((height=0, column=0))
for each column c:
height = dp(r, c)
c1 = c
while stack.top.height > height:
c1 = stack.top.column
stack.pop()
if stack.top.height != height:
stack.push((height=height, column=c1))
for item in stack:
a = (c - item.column + 1) * item.height
area = max(area, a)
It is also possible to solve the problem in O(RC) using three DP’s:
The three recurrence relations are:
h(r, c) = h(r-1, c)+1 otherwise
l(r, 0) = 0
l(r, c) = min(l(r − 1, c), c − p) otherwise
r(r,C+1) = 0
where p is the column of the previous 0 as we populate l from left-right and r from right-left.
The answer is then:
This works because of the observation that the largest rectangle will always touch a 0 (considering the edge as being covered in 0's) on all four sides. By considering all rectangles with at least top, left and right touching a 0, we cover all candidate rectangles. Generate every possible rectangle. You can do this by iterating through every pair of points (r1,c1) (r2,c2) with r1 ≤ r2 and c1 ≤ c2 (can be done with 4 for loops). If a rectangle does not contain a 0, you compare the area to the largest area found so far.
Note: I adapted the above from an answer I wrote up here - refer to the section "Ben's Mom". In that writeup, the 0's are trees. That writeup also has better formatting.