二维区域和检索 - 可变
难度:
标签:
题目描述
代码结果
运行时间: 55 ms, 内存: 19.8 MB
/**
* LeetCode 308: Range Sum Query 2D - Mutable
*
* 题目思路:
* 1. 本题的复杂度较高,Java Stream 在处理更新和查询时不是最佳选择。
* 2. 为了利用 Java Stream 进行处理,我们将主要使用集合和流的操作来简化代码。
*/
import java.util.*;
import java.util.stream.*;
public class NumMatrixStream {
private int[][] matrix;
private Map<Integer, Integer> bit;
private int m, n;
public NumMatrixStream(int[][] matrix) {
if (matrix.length == 0 || matrix[0].length == 0) return;
this.matrix = new int[matrix.length][matrix[0].length];
this.m = matrix.length;
this.n = matrix[0].length;
this.bit = new HashMap<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
update(i, j, matrix[i][j]);
}
}
}
public void update(int row, int col, int val) {
int delta = val - matrix[row][col];
matrix[row][col] = val;
IntStream.iterate(col + 1, j -> j <= n, j -> j + (j & -j))
.forEach(j -> bit.merge(row * n + j, delta, Integer::sum));
}
private int prefixSum(int row, int col) {
return IntStream.iterate(col, j -> j > 0, j -> j - (j & -j))
.map(j -> bit.getOrDefault(row * n + j, 0))
.sum();
}
public int sumRegion(int row1, int col1, int row2, int col2) {
return IntStream.rangeClosed(row1, row2)
.map(i -> prefixSum(i, col2 + 1) - prefixSum(i, col1))
.sum();
}
}
解释
方法:
该题解使用了前缀和技巧。在构造函数中,通过对每一行计算前缀和,并将结果存储在二维数组 P 中。当需要更新某个元素时,只需要更新对应行的前缀和数组即可。在计算区域和时,可以利用前缀和的性质,对于每一行,用区域右端点的前缀和减去左端点的前缀和,然后将所有行的结果累加起来,即可得到最终的区域和。
时间复杂度:
构造函数: O(mn), update: O(n), sumRegion: O(m)
空间复杂度:
O(mn)
代码细节讲解
🦆
在构造函数中创建前缀和数组时,你是如何处理边界情况,比如矩阵为空或只有一行/一列的情况?
▷🦆
你的算法在执行 update 操作时是否考虑了可能对同一位置进行多次更新,这是否会影响累计的前缀和结果?
▷🦆
在 sumRegion 函数中,你是如何确保计算的区域索引不会超出矩阵的有效边界?
▷🦆
当执行 update 操作后,你只更新了该行的前缀和,这种方法是否考虑了列之间的依赖关系?
▷相关问题
二维区域和检索 - 矩阵不可变
给定一个二维矩阵 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 (蓝色矩形框的元素总和)
提示:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 200
-105 <= matrix[i][j] <= 105
0 <= row1 <= row2 < m
0 <= col1 <= col2 < n
- 最多调用
104
次sumRegion
方法
区域和检索 - 数组可修改
给你一个数组 nums
,请你完成两类查询。
- 其中一类查询要求 更新 数组
nums
下标对应的值 - 另一类查询要求返回数组
nums
中索引left
和索引right
之间( 包含 )的nums元素的 和 ,其中left <= right
实现 NumArray
类:
NumArray(int[] nums)
用整数数组nums
初始化对象void update(int index, int val)
将nums[index]
的值 更新 为val
int sumRange(int left, int right)
返回数组nums
中索引left
和索引right
之间( 包含 )的nums元素的 和 (即,nums[left] + nums[left + 1], ..., nums[right]
)
示例 1:
输入: ["NumArray", "sumRange", "update", "sumRange"] [[[1, 3, 5]], [0, 2], [1, 2], [0, 2]] 输出: [null, 9, null, 8] 解释: NumArray numArray = new NumArray([1, 3, 5]); numArray.sumRange(0, 2); // 返回 1 + 3 + 5 = 9 numArray.update(1, 2); // nums = [1,2,5] numArray.sumRange(0, 2); // 返回 1 + 2 + 5 = 8
提示:
1 <= nums.length <= 3 * 104
-100 <= nums[i] <= 100
0 <= index < nums.length
-100 <= val <= 100
0 <= left <= right < nums.length
- 调用
update
和sumRange
方法次数不大于3 * 104