题意
题解
暴力
前缀和维护矩形区域内 1 1 1 的数量,枚举矩形的左上顶点与右下顶点,若矩形区域内 1 1 1 的求和等于矩形面积,则计入答案。当不可能出现全 1 1 1 矩形时,需要即时停止枚举;即固定某左上顶点枚举右下顶点时,右边界 m a t mat mat 出现 0 0 0 则收缩右下点的右边界,若下边界第一个位置出现 0 0 0 则枚举下一个左上顶点。
class Solution
{
#define maxn 155
public:
int sum[maxn][maxn];
int numSubmat(vector<vector<int>> &mat)
{
int n = mat.size(), m = mat[0].size();
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
sum[i + 1][j + 1] = sum[i][j + 1] + sum[i + 1][j] - sum[i][j] + mat[i][j];
}
}
int res = 0;
for (int x1 = 1; x1 <= n; x1++)
{
for (int y1 = 1; y1 <= m; y1++)
{
for (int x2 = x1; x2 <= n; x2++)
{
if (mat[x2 - 1][y1 - 1] == 0) break;
int limit = m;
for (int y2 = y1; y2 <= limit; y2++)
{
if (sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1] == (x2 - x1 + 1) * (y2 - y1 + 1)) ++res;
else
{
limit = y2 - 1;
break;
}
}
}
}
}
return res;
}
};
优化的暴力
考虑到固定左上顶点时,枚举的右下顶点一定是行连续的,那么对于每一行,用前缀和维护顶点右侧连续的 1 1 1 的个数即可,此数量即以此顶点为矩形左上顶点时,在这一行可枚举的右下顶点数量。复杂度由 O ( n 2 m 2 ) O(n^2m^2) O(n2m2) 降为 O ( n 2 m ) O(n^2m) O(n2m)。
class Solution
{
#define maxn 155
public:
int sum[maxn][maxn];
int numSubmat(vector<vector<int>> &mat)
{
int n = mat.size(), m = mat[0].size();
for (int i = n - 1; i >= 0; i--)
{
int s = 0;
for (int j = m - 1; j >= 0; j--)
{
if (mat[i][j] == 0) s = 0;
else ++s;
sum[i][j] = s;
}
}
int res = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
int num = INT_MAX;
for (int k = i; k < n; k++)
{
num = min(num, sum[k][j]);
if (num == 0) break;
res += num;
}
}
}
return res;
}
};