algorithmgraphcombinatoricsrectanglesdiscrete-mathematics

Count the number of positions in a matrix which form a rectangle


I have a square matrix which contains only 0's and 1's. For example,

1  0  1  1  1
1  1  0  0  1
1  0  1  1  0
0  1  1  1  1
1  0  1  1  1

I would like to count the number of rectangles which have 1's as their vertices and which edges are parallel to rows and columns of the matrix. It is allowed to have 0's on the rectangle's edge. Here is an example of such a rectangle (its vertices are in square brackets)

[1]  0  1  1  [1]
 1   1  0  0   1
 1   0  1  1   0
 0   1  1  1   1
[1]  0  1  1  [1]

I have looked into link1 and link2 but still have no clue..


Solution

  • In the worst case the matrix has no zeroes and thus it can have O(𝑛2) top-left corners combined with as many bottom-right corners, making for O(𝑛4) rectangles.

    So if you would have to output each rectangle, the time complexity would be O(𝑛4). But as you only need to count the rectangles and not produce the rectangles themselves, you can save some time and do it with a time complexity of O(𝑛3).

    The idea is to select every possible pair of rows, and then count how many columns have a 1 in both selected rows. Each combination of 2x2 should be accounted for. This is a triangular number: if the count of 1-1 pairs is 𝑘, then the number of rectangles that can be made with those is 𝑘(𝑘-1)/2.

    Implementation in JavaScript:

    function countRectangles(rect) {
        let count = 0;
        for (let y2 = 1; y2 < rect.length; y2++) {
            for (let y1 = 0; y1 < y2; y1++) {
                let pairs = 0;
                for (let x = 0; x < rect[0].length; x++) {
                    if (rect[y1][x] + rect[y2][x] == 2) {
                        pairs++;
                    }
                }
                // Count in how many ways 2 pairs of corners can be combined
                count += pairs * (pairs - 1) / 2;
            }
        }
        return count;
    }
    
    const rect = [
        [1,  0,  1,  1,  1],
        [1,  1,  0,  0,  1],
        [1,  0,  1,  1,  0],
        [0,  1,  1,  1,  1],
        [1,  0,  1,  1,  1],
    ]
    
    console.log(countRectangles(rect)); // 22