题目描述
给定一个二维矩阵 matrix,以下类型的多个请求:
●计算其子矩形范围内元素的总和,该子矩阵的 左上角 为 (row1, col1) ,右下角 为 (row2, col2) 。
实现 NumMatrix 类:
●NumMatrix(int[][] matrix)
给定整数矩阵 matrix 进行初始化
●int sumRegion(int row1, int col1, int row2, int col2)
返回 左上角 (row1, col1) 、右下角 (row2, col2) 所描述的子矩阵的元素 总和 。
简单来说就是根据矩阵给两个坐标,左上和右下,确定一个子矩阵,然后计算子矩阵中所有元素的和。
解法: 前缀和
将矩阵重新计算,每个位置填上以这个位置的坐标为右下角,(0,0)为左上角的子矩阵中所有元素的和。建议预计算时在矩阵左侧和上侧填上一圈0,这样可以不用计算边界条件(代码实现中本人直接在原数组上修改,因此需要根据情况计算边界)。
在计算前缀和时,可以通过公式:
preSumArray[m][n]=matrix[m][n]+preSumArray[m-1][n]+preSumArray[m][n-1]-preSumArray[m-1][n-1]
在计算子矩阵和时,通过公式:
sum[m][n]=preSumArray[m][n]-preSumArray[m][n-1]-preSumArray[m-1][n]+preSumArray[m-1][n-1]
代码:
class NumMatrix {
public:
vector<vector<int>> matrix;
NumMatrix(vector<vector<int>>& matrix) {
int m=matrix.size();
int n=matrix[0].size();
// 更新矩阵 计算前缀和
for(int i=1; i<m; i++){
matrix[i][0]+=matrix[i-1][0];
}
for(int j=1; j<n; j++){
matrix[0][j]+=matrix[0][j-1];
}
for(int i=1; i<m; i++){
for(int j=1; j<n; j++){
matrix[i][j]+=matrix[i-1][j]+matrix[i][j-1]-matrix[i-1][j-1];
}
}
this->matrix=matrix;
}
int sumRegion(int row1, int col1, int row2, int col2) {
// 1. 暴力解法 计算量太大, 太多重复计算, 没必要
// 2. 前缀和, 先预处理一遍数组,每个位置的值变成以这个位置为右下角的矩阵之和
// 之后再计算的时候
// answer = mat[m][n]-mat[m-1][n]-mat[m][n-1]+mat[m-1][n-1]
// 此外还需要考虑边界情况
// 直接在原数组上进行修改
int m=matrix.size();
int n=matrix[0].size();
if(row1<0 || row2>=m || col1<0 || col2>=n || row1>row2 || col1>col2) return 0;
// 判断数据是否正确
// 1. 左上坐标在矩阵的左上角
if(row1==0 && col1==0){
return matrix[row2][col2];
}
// 2. 左上坐标在矩阵最左侧
if(col1==0){
return matrix[row2][col2]-matrix[row1-1][col2];
}
// 3. 左上坐标在矩阵最上
if(row1==0){
return matrix[row2][col2]-matrix[row2][col1-1];
}
// 4. 左上坐标不贴边
return matrix[row2][col2]-matrix[row1-1][col2]-matrix[row2][col1-1]+matrix[row1-1][col1-1];
}
};