今天是三月二号,这个月力扣每日一题打卡第2天。两天来连续遇到前缀和解决一个区间内的和的问题,觉得还是比较高频的所以来记录一下这两道题目的思路和解法。
来一段狂神经典语录激励一下自己:
只要学不死,就往死里学!!
力扣第303题: 区域和检索-数组不可变
给定一个整数数组 nums,求出数组从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点。
实现 NumArray 类:
- NumArray(int[] nums) 使用数组 nums 初始化对象
- int sumRange(int i, int j) 返回数组 nums 从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点(也就是 sum(nums[i], nums[i + 1], … , nums[j]))
输入:
["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))
阅读题目可以得知,这道题目让我们求一个区间的和,求区间的和我们可以用preNum(前缀和)来求解。
preSum 方法能快速计算指定区间段 i - ji−j 的元素之和。它的计算方法是从左向右遍历数组,当遍历到数组的 ii 位置时,preSum 表示 ii 位置左边的元素之和。
假设数组长度为 NN,我们定义一个长度为 N+1N+1 的 preSum 数组,preSum[i] 表示该元素左边所有元素之和(不包含 i 元素)。然后遍历一次数组,累加区间 [0, i)[0,i) 范围内的元素,可以得到 preSum 数组。
代码实现:
class NumArray {
//利用前缀和来求一个区间范围内的和
private int[] preNum;
public NumArray(int[] nums) {
preNum = new int[nums.length+1];
for(int i=0;i<nums.length;i++){
preNum[i+1] = preNum[i] + nums[i];
}
}
public int sumRange(int i, int j) {
return preNum[j+1] - preNum[i];
}
}
/**
* Your NumArray object will be instantiated and called as such:
* NumArray obj = new NumArray(nums);
* int param_1 = obj.sumRange(i,j);
*/
力扣第304题: 二维区域和检索-矩阵不可变
示例:
给定 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
这道题是「303. 区域和检索 - 数组不可变」的进阶,第 303 题是在一维数组中做区域和检索,这道题是在二维矩阵中做区域和检索。
这道题有两种解法,分别是对每一行计算一维前缀和,以及对整个矩阵计算二维前缀和。
方法一:一维前缀和
第 303 题中,初始化时对数组计算前缀和,每次检索即可在 O(1) 的时间内得到结果。可以将第 303 题的做法应用于这道题,初始化时对矩阵的每一行计算前缀和,检索时对二维区域中的每一行计算子数组和,然后对每一行的子数组和计算总和。
具体实现方面,创建 m 行 n+1 列的二维数组,其中 m 和 n 分别是矩阵的行数和列数,preNum[i] 为matrix[i] 的前缀和数组。
代码实现:
class NumMatrix {
//与一维的差不多,只是多了一个外层循环而已
private int[][] preNum;
public NumMatrix(int[][] matrix) {
int m = matrix.length;
//这里是一个坑,必须判断数组是否是大于0,否则的话会薄数组为空的异常,切记!
if(m>0){
int n = matrix[0].length;
preNum = new int[m][n+1];
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
preNum[i][j+1] = preNum[i][j] + matrix[i][j];
}
}
}
}
public int sumRegion(int row1, int col1, int row2, int col2) {
int sum = 0;
for(int i=row1;i<=row2;i++){
sum += preNum[i][col2+1]-preNum[i][col1];
}
return sum;
}
}
/**
* Your NumMatrix object will be instantiated and called as such:
* NumMatrix obj = new NumMatrix(matrix);
* int param_1 = obj.sumRegion(row1,col1,row2,col2);
*/
所有牛逼的人都有一段苦逼的岁月!但是你只要像SB一样去坚持,终将牛逼!