题目描述
给你一个 m * n
的矩阵 mat
和一个整数 K
,请你返回一个矩阵 answer
,其中每个 answer[i][j]
是所有满足下述条件的元素 mat[r][c]
的和:i - K <= r <= i + K, j - K <= c <= j + K
且 (r, c)
在矩阵内。
样例
输入:mat = [[1,2,3],[4,5,6],[7,8,9]], K = 1
输出:[[12,21,16],[27,45,33],[24,39,28]]
输入:mat = [[1,2,3],[4,5,6],[7,8,9]], K = 2
输出:[[45,45,45],[45,45,45],[45,45,45]]
限制
m == mat.length
n == mat[i].length
1 <= m, n, K <= 100
1 <= mat[i][j] <= 100
算法
(矩阵前缀和) $O(mn)$
- 在原数组的基础上,求出前缀和矩阵。递推的一般形式为:
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + mat[i][j]
。其中注意特殊处理边界。 - 求子矩阵和的时候,可以直接利用前缀和矩阵,设矩阵的左上角和右下角分别为
(x1, y1)
以及(x2, y2)
,则res = sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1]
。注意特殊处理x1
和y1
为 0 的边界情况。 - 对应到此题,就可以轻松的利用上述公式,来求解每给点的答案。
时间复杂度
- 预处理前缀和矩阵的时间复杂度为 $O(mn)$,求解每个位置的答案时间为常数,故总时间复杂度为 $O(mn)$。
空间复杂度
- 需要额外 $O(mn)$ 的空间存储答案。
C++ 代码
class Solution {
public:
vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int K) {
int m = mat.size(), n = mat[0].size();
for (int i = 1; i < m; i++)
mat[i][0] += mat[i - 1][0];
for (int j = 1; j < n; j++)
mat[0][j] += mat[0][j - 1];
for (int i = 1; i < m; i++)
for (int j = 1; j < n; j++)
mat[i][j] += mat[i - 1][j] + mat[i][j - 1] - mat[i - 1][j - 1];
vector<vector<int>> ans(m, vector<int>(n));
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
int x = min(m - 1, i + K);
int y = min(n - 1, j + K);
ans[i][j] = mat[x][y];
if (i - K - 1 >= 0)
ans[i][j] -= mat[i - K - 1][y];
if (j - K - 1 >= 0)
ans[i][j] -= mat[x][j - K - 1];
if (i - K - 1 >= 0 && j - K - 1 >= 0)
ans[i][j] += mat[i - K - 1][j - K - 1];
}
return ans;
}
};