利用前缀和来求一个区间内的和

今天是三月二号,这个月力扣每日一题打卡第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一样去坚持,终将牛逼!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值