Largest rectangle of 1's in 2d binary matrix

后端 未结 6 579
野性不改
野性不改 2020-12-07 17:56

There is a problem to find the maximum area of the 1 in the 0-1 matrix. In this problem there are two cases:

  1. area to be measure is of shape square. that\'s

相关标签:
6条回答
  • 2020-12-07 18:34

    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.

    0 讨论(0)
  • 2020-12-07 18:43

    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.

    0 讨论(0)
  • 2020-12-07 18:44
    **
    
    //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;
        }
    
    
    }
    
    0 讨论(0)
  • 2020-12-07 18:49

    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;
    } 
    
    0 讨论(0)
  • 2020-12-07 18:54
    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-07 18:55

    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)).

    • dp(r, 0) = 0
    • dp(0, c) = 0
    • dp(r,c) = dp(r−1,c)+dp(r,c−1)−dp(r−1,c−1)+(matrix[r][c]?0:1)

    Then the number of 0's in ((r1, c1), (r2, c2)) is

    • nzeroes(r1,c1,r2,c2) = dp[r2][c2]−dp[r1 −1][c2]−dp[r2][c1 −1]+dp[r1 −1][c1 −1]

    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:

    • dp(r, 0) = 0
    • dp(r, c) = 0 if matrix[r][c] == 0
    • dp(r, c) = dp(r-1, c) + 1 otherwise

    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:

    • h(r, c): if we start at (r, c) and go upwards, how many 1 cells do we find before the first 0?
    • l(r, c): how far left can we extend a rectangle with bottom-right corner at (r, c) and height h(r, c)?
    • r(r,c): how far right can we extend a rectangle with bottom-left corner at (r, c) and height h(r, c)?

    The three recurrence relations are:

    • h(0, c) = 0
    • h(r, c) = 0 if matrix[r][c] == 0
    • h(r, c) = h(r-1, c)+1 otherwise

    • l(r, 0) = 0

    • l(r, c) = c-p if matrix[r-1][c] == 0
    • l(r, c) = min(l(r − 1, c), c − p) otherwise

    • r(r,C+1) = 0

    • r(r,c) = p-c if matrix[r-1][c] == 0
    • r(r,c) = min(r(r − 1, c), p − c) otherwise

    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:

    • max_r,c(h(r, c) ∗ (l(r, c) + r(r, c) − 1))

    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.

    0 讨论(0)
提交回复
热议问题