题目链接:https://leetcode.cn/problems/maximum-side-length-of-a-square-with-sum-less-than-or-equal-to-threshold/
题目大意:给出一个m*n
矩阵mat[][]
,求最大的满足以下条件的正方形的边长:正方形内元素之和小于等于threshold
思路:开始以为是DP,后来发现是用前缀和做。二维的前缀和还是第一次写。对于一个矩阵,从左上角到某一个点(i, j)
的和为
pre[i][j] = pre[i-1][j] + pre[i][j-1] - pre[i-1][j-1] + mat[mi][mj]
此处的mi, mj
是考虑到mat[][]
坐标从0
开始,pre[][]
坐标从1
开始做的对应的转换。
因此第一次遍历计算所有前缀和。随后对于c
,从最大的可能min(m, n)
开始再次遍历,计算可能的c*c
大小的正方形内元素之和,与threshold
对比。正方形元素和的计算如下
int sumRect(int x1, int y1, int x2, int y2) {
return pre[x2][y2] - pre[x1-1][y2] - pre[x2][y1-1] + pre[x1-1][y1-1];
}
找到一个符合的c
即可返回。
完整代码
class Solution {
public:
int pre[301][301];
int sumRect(int x1, int y1, int x2, int y2) {
return pre[x2][y2] - pre[x1-1][y2] - pre[x2][y1-1] + pre[x1-1][y1-1];
}
int maxSideLength(vector<vector<int>>& mat, int threshold) {
int m = mat.size(), n = mat[0].size();
memset(pre, 0, sizeof(pre));
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
int mi = i-1, mj = j-1;
pre[i][j] = pre[i-1][j] + pre[i][j-1] - pre[i-1][j-1] + mat[mi][mj];
}
}
int c = min(m, n);
int ret = 0;
while (c > 0) {
for (int sx = 1; sx <= m; sx++) {
for (int sy = 1; sy <= n; sy++) {
if (sx+c-1 <= m && sy+c-1 <= n) {
if (sumRect(sx, sy, sx+c-1, sy+c-1) <= threshold) {
ret = c;
return ret;
}
}
}
}
c--;
}
return ret;
}
};