1. 题⽬链接:1314.矩阵区域和
2. 题⽬描述:
3. 解法:
算法思路:
⼆维前缀和的简单应⽤题,关键就是我们在填写结果矩阵的时候,要找到原矩阵对应区域的「左上 ⻆」以及「右下⻆」的坐标(推荐⼤家画图)
左上⻆坐标: x1 = i - k,y1 = j - k ,但是由于会「超过矩阵」的范围,因此需要对0 取⼀个max 。因此修正后的坐标为: x1 = max(0, i - k), y1 = max(0, j - k) ;
右下⻆坐标: x1 = i + k,y1 = j + k ,但是由于会「超过矩阵」的范围,因此需要对m - 1 ,以及n - 1 取⼀个min 。因此修正后的坐标为: x2 = min(m - 1, i + k), y2 = min(n - 1, j + k) 。
然后将求出来的坐标代⼊到「⼆维前缀和矩阵」的计算公式上即可~(但是要注意下标的映射关 系)
C++算法代码:
class Solution
{
public:
vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k)
{
int m=mat.size(),n=mat[0].size();
//为了避免越界,行列都多开一行(列)
//二维前缀和表
vector<vector<int>>qzh(m+1,vector<int>(n+1));
for(int i=1;i<m+1;i++)
{
for(int j=1;j<n+1;j++)
{
//此题数据的下标从1开始,故mat数据坐标要-1
qzh[i][j]=qzh[i-1][j]+qzh[i][j-1]-qzh[i-1][j-1]+mat[i-1][j-1];
}
}
//答案数组
vector<vector<int>>answer(m,vector<int>(n));
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
//防止越界访问,越界点则定在边界上
//为了坐标与前缀和数组小标==下标对应,所以都要+1
int x1=max(0,i-k)+1,y1=max(0,j-k)+1;
int x2=min(m-1,i+k)+1,y2=min(n-1,j+k)+1;
answer[i][j]=qzh[x2][y2]-qzh[x2][y1-1]-qzh[x1-1][y2]+qzh[x1-1][y1-1];
}
}
return answer;
}
};
Java算法代码:
class Solution {
public int[][] matrixBlockSum(int[][] mat, int k) {
int m = mat.length, n = mat[0].length;
// 1. 预处理前缀和矩阵
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] +
mat[i - 1][j - 1];
// 2. 使⽤
int[][] ret = new int[m][n];
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
int x1 = Math.max(0, i - k) + 1, y1 = Math.max(0, j - k) + 1;
int x2 = Math.min(m - 1, i + k) + 1, y2 = Math.min(n - 1, j +
k) + 1;
ret[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] +
dp[x1 - 1][y1 - 1];
}
return ret;
}
}