给定一个二维矩阵 matrix,以下类型的多个请求:
- 计算其子矩形范围内元素的总和,该子矩阵的 左上角 为 (row1, col1) ,右下角 为 (row2, col2) 。
实现 NumMatrix 类:
- NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
- int sumRegion(int row1, int col1, int row2, int col2) 返回 左上角 (row1, col1) 、右下角 (row2, col2) 所描述的子矩阵的元素 总和 。
示例1:
输入:
[“NumMatrix”,”sumRegion”,”sumRegion”,”sumRegion”]
[[[[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]],[2,1,4,3],[1,1,2,2],[1,2,2,4]]
输出:
[null, 8, 11, 12]
解释:
NumMatrix numMatrix = new NumMatrix([[3,0,1,4,2],[5,6,3,2,1],[1,2,0,1,5],[4,1,0,1,7],[1,0,3,0,5]]);
numMatrix.sumRegion(2, 1, 4, 3); // return 8 (红色矩形框的元素总和)
numMatrix.sumRegion(1, 1, 2, 2); // return 11 (绿色矩形框的元素总和)
numMatrix.sumRegion(1, 2, 2, 4); // return 12 (蓝色矩形框的元素总和)
常规算法:遍历求和
class NumMatrix {private int[][] matrix;public NumMatrix(int[][] matrix) {this.matrix = matrix;}public int sumRegion(int row1, int col1, int row2, int col2) {int sum = 0;for (int i = row1; i <= row2; i++) {for (int j = col1; j <= col2; j++) {sum += matrix[i][j];}}return sum;}}
但是此题可以看做 303. 区域和检索 - 数组不可变 的升级,同理可以考虑使用前缀和技巧

比如想得到红色矩阵的和,可以先分别计算绿色矩阵的和,蓝色矩阵的和,黄色矩阵的和,粉色矩阵的和,那么:
红色矩阵的和 = 绿色矩阵的和 - 蓝色矩阵的和 - 黄色矩阵的和 + 粉色矩阵的和
如何构建二维数组的前缀和数组呢?
构建一维数组的前缀和数组有如下两个模板:
int[] sums;public NumArray(int[] nums) {sums = new int[nums.length + 1];// 遍历 nums 初始化 sumsfor (int i = 0; i < nums.length; i++) {sums[i + 1] = sums[i] + nums[i];}}public NumArray(int[] nums) {sums = new int[nums.length + 1];// 遍历 sums 初始化 sumsfor (int i = 1; i <= sums.length; i++) {sums[i] = sums[i - 1] + nums[i - 1];}}
同理构建二维数组的前缀和数组也有模板:
int[][] sums;public NumMatrix(int[][] matrix) {// 计算行数int row = matrix.length;// 计算列数(需判断列是否存在)int col = row == 0 ? 0 : matrix[0].length;sums = new int[row + 1][col + 1];// 遍历 sums 构建 sumsfor(int i = 1; i <= row; i++) {for (int j = 1; j <= col; j++) {sums[i][j] = sums[i-1][j] + sums[i][j-1] - sums[i-1][j-1] + matrix[i-1][j-1];}}}
利用一维数组前缀和数组求和模板:
public int sumRange(int i, int j) {return sums[j + 1] - sums[i];}
同理利用二维数组前缀和数组求和模板:
public int sumRegion(int row1, int col1, int row2, int col2) {// 红色矩阵的和 = 绿色矩阵的和 - 蓝色矩阵的和 - 黄色矩阵的和 + 粉色矩阵的和return sums[row2 + 1][col2 + 1] - sums[rol1][col2 + 1] - sums[rol2 + 1][col1] + sums[row1][col1];}
完整算法:
class NumMatrix {int[][] sums;public NumMatrix(int[][] matrix) {// 计算行数int row = matrix.length;// 计算列数(需判断列是否存在)int col = row == 0 ? 0 : matrix[0].length;sums = new int[row + 1][col + 1];// 遍历 sums 构建 sumsfor(int i = 1; i <= row; i++) {for (int j = 1; j <= col; j++) {sums[i][j] = sums[i-1][j] + sums[i][j-1] - sums[i-1][j-1] + matrix[i-1][j-1];}}}public int sumRegion(int row1, int col1, int row2, int col2) {// 红色矩阵的和 = 绿色矩阵的和 - 蓝色矩阵的和 - 黄色矩阵的和 + 粉色矩阵的和return sums[row2 + 1][col2 + 1] - sums[row1][col2 + 1] - sums[row2 + 1][col1] + sums[row1][col1];}}
