区域和检索 - 数组不可变
难度:
标签:
题目描述
给定一个整数数组 nums
,处理以下类型的多个查询:
- 计算索引
left
和right
(包含left
和right
)之间的nums
元素的 和 ,其中left <= right
实现 NumArray
类:
NumArray(int[] nums)
使用数组nums
初始化对象int sumRange(int i, int j)
返回数组nums
中索引left
和right
之间的元素的 总和 ,包含left
和right
两点(也就是nums[left] + nums[left + 1] + ... + nums[right]
)
示例 1:
输入: ["NumArray", "sumRange", "sumRange", "sumRange"] [[[-2, 0, 3, -5, 2, -1]], [0, 2], [2, 5], [0, 5]] 输出: [null, 1, -1, -3] 解释: NumArray numArray = new NumArray([-2, 0, 3, -5, 2, -1]); numArray.sumRange(0, 2); // return 1 ((-2) + 0 + 3) numArray.sumRange(2, 5); // return -1 (3 + (-5) + 2 + (-1)) numArray.sumRange(0, 5); // return -3 ((-2) + 0 + 3 + (-5) + 2 + (-1))
提示:
1 <= nums.length <= 104
-105 <= nums[i] <= 105
0 <= i <= j < nums.length
- 最多调用
104
次sumRange
方法
代码结果
运行时间: 60 ms, 内存: 20.0 MB
// Java Solution using Java Stream
// 题目思路:
// 我们可以利用 Java Stream API 提供的工具来简化计算。尽管这种方法可能不会有前缀和数组的高效,
// 但可以利用 Stream 的特性进行元素的累加计算。
import java.util.Arrays;
public class NumArrayStream {
private int[] nums;
// 构造函数,保存数组
public NumArrayStream(int[] nums) {
this.nums = nums;
}
// 计算区间 [left, right] 的元素和
public int sumRange(int left, int right) {
return Arrays.stream(nums, left, right + 1).sum();
}
}
解释
方法:
这个题解使用了前缀和的思想。在构造函数中,先预处理计算出数组 nums 的前缀和数组 presum,其中 presum[i] 表示 nums[0] 到 nums[i-1] 的累加和。在 sumRange 查询函数中,利用前缀和数组快速计算出区间 [left, right] 的累加和,只需要用 presum[right+1] 减去 presum[left] 即可得到结果。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在前缀和数组`presum`中,索引0的值被初始化为0,这样的设计有什么特别的用处吗?
▷🦆
在构造`NumArray`类时,计算前缀和数组`presum`的循环中,`presum[i] = presum[i-1] + nums[i-1]`这一步是如何确保数组索引不会越界的?
▷🦆
在方法`sumRange`中,直接使用`presum[right+1] - presum[left]`来获取区间和的原理是什么?能否详细解释这种计算方式的数学依据?
▷🦆
如果输入的索引`left`或`right`不在数组`nums`的有效范围内,`sumRange`方法会如何处理?是否有错误处理机制?
▷相关问题
二维区域和检索 - 矩阵不可变
给定一个二维矩阵 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