1、题目描述
2、解题思路
本题不严谨,请忽视“轴对称”这三个字。
假设一个网格如下:
我们最低行往上数,先锁定一条边:
然后往上一行一行地找有没有和他能组成角矩形的边,发现一个都没有。
于是我换一个边:
然后往上扫视,发现还真的有可以和他组成角矩形的边:
于是,一个角矩形就挖掘出来了。
再换一个边:
往上扫视一下,发现没有能和它组成角矩形的边。
至此,最后一行处理完毕。接着处理倒数第二行。
以此类推,按照这样的步骤可以找出所有的角矩形
由于我们的代码一般都是从上到下从左到右遍历二维数组,因此,我们稍微改动一下算法流程,本质逻辑和上面是一样的。
假设行数为 rows,列数为 cols 。
在第 i 行的索引 j 找到一个 1,于是我们从第 i 行的 [j+1, cols] 中找另一个 1,假设在 k 位置找到了。
于是,我们找到了一条边 [j, k],我们就得往上面的行找,如果 [0, i-1] 行中,有 m 行的 j 索引和 k 索引都是 1。
于是我们就找到了 m 个角矩形。
因此,我们得定义一个数据结构来存储这样的信息:在 i 行上面的行中,grid[?][j] 和 grid[?][k] 都为 1 的行有多少行,这里的 ? 指的是第 0 行到第 i-1 行。
设 board[i][j] 表示遍历到的行前面的行中,位置 i 和 j 都为 1 的行的个数。
当遍历到某一行的 grid[?][j] 和 grid[?][k] 为 1,那么,角矩形的个数 ans = ans + board[i][j].
描述如果看不懂,可以看代码。
3、解题代码
class Solution {
public int countCornerRectangles(int[][] grid) {
int rows = grid.length;
int cols = grid[0].length;
// border[i][j] 表示从不包含当前行的前面所有行中,列的 i 索引和 j 索引都为 1 的行的个数
int[][] border = new int[rows + 1][cols + 1];
int ans = 0; // 总共角矩形的个数
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (grid[i][j] == 1) {
for (int k = j + 1; k < cols; k++) {
if (grid[i][k] == 1) {
// 找到了角矩形的一个底边
ans += border[j][k];
// 第 0 行到第 i 行的每一行中,列索引 j 和 k 都为 1 的行的个数加一
border[j][k]++;
}
}
}
}
}
return ans;
}
}