304. 二维区域和检索 - 矩阵不可变
给定一个二维矩阵,计算其子矩形范围内元素的总和,该子矩阵的左上角为 (row1, col1)
,右下角为 (row2, col2)
。
上图子矩阵左上角 (row1, col1) = (2, 1)
,右下角 (row2, col2) = (4, 3)
,该子矩形内元素的总和为 8
。
示例:
给定 matrix = [
[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]
]
sumRegion(2, 1, 4, 3) -> 8
sumRegion(1, 1, 2, 2) -> 11
sumRegion(1, 2, 2, 4) -> 12
提示:
- 你可以假设矩阵不可变。
- 会多次调用
sumRegion
方法。 - 你可以假设
row1 ≤ row2
且col1 ≤ col2
。
方法一:前缀和数组
解题思路
解决两个问题,题目就搞定了。
- 一维数组的前缀和很好理解,二维数组前缀和应该怎么表示呢?
- 如何根据前缀和数组求出对应区域的元素总和?
下面来解决这两个问题。
- 定义
preSums[i + 1][j + 1]
表示从matrix[0][0]
到matrix[i][j]
矩阵的元素总和。通过累加“上”和“左”矩形的元素总和减去重复区域再加上当前坐标的值。
具体公式:preSums[i + 1][j + 1] = preSums[i + 1][j] + preSums[i][j + 1] - preSums[i][j] + matrix[i][j];
- 问题 2 的思路与计算前缀和思路相反,通过减去“上”和“左”矩形的元素总和再加上多减去的部分。
具体公式:preSums[row2 + 1][col2 + 1] - preSums[row2 + 1][col1] - preSums[row1][col2 + 1] + preSums[row1][col1]
;
参考代码
class NumMatrix {
private int[][] preSums;
public NumMatrix(int[][] matrix) {
int m = matrix.length;
if(m > 0) {
int n = matrix[0].length;
preSums = new int[m + 1][n + 1];
for (int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
preSums[i + 1][j + 1] = preSums[i + 1][j] + preSums[i][j + 1] - preSums[i][j] + matrix[i][j];
}
}
}
}
public int sumRegion(int row1, int col1, int row2, int col2) {
return preSums[row2 + 1][col2 + 1] - preSums[row2 + 1][col1] - preSums[row1][col2 + 1] + preSums[row1][col1];
}
}