数组的前缀和技巧

191 阅读3分钟

前缀和算法用于快速,频繁计算一个索引区间内的元素之和

1 一维数组中的前缀和算法

见LeetCode第303题[区域和检索-数组不可变].

题目描述

给定一个整数数组 nums,处理以下类型的多个查询:

  1. 计算索引 leftright (包含 leftright)之间的 nums 元素的 ,其中 left <= right

实现 NumArray 类:

  • NumArray(int[] nums) 使用数组 nums 初始化对象
  • int sumRange(int i, int j) 返回数组 nums 中索引 leftright 之间的元素的 总和 ,包含 leftright 两点(也就是 nums[left] + nums[left + 1] + ... + nums[right] )

我的思路

  • 每次都搜索指定区间,然后遍历区间得到元素之和,时间复杂度比较高,达到O(counts * N),其中counts表示搜索的次数
  • 可以计算从[0, end]这样一个区间的和,存储到临时结果集中
  • 那么[start, end]这样一个闭区间的和,可以得出为preSum[end] - preSum[start] + nums[start]
class NumArray {

    private int[] nums;
    private int[] preSum;

    public NumArray(int[] nums) {
        this.nums = nums;
        preSum = new int[nums.length];
        preSum[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            preSum[i] = preSum[i - 1] + nums[i];
        }
    }
    
    public int sumRange(int left, int right) {
        return preSum[right] - preSum[left] + nums[left];
    }
}
  • 时间复杂度:不管调用多少次sumRange()方法,只会在对象初始化的时候,初始化preSum,时间复杂度为O(N)
  • 空间复杂度:使用了额外数组preSum来记录当前元素的前缀和,空间复杂度为O(N)

2 二维数组中的前缀和

见LeetCode第304题[二维区域和检索-矩阵不可变]

题目描述

给定一个二维矩阵 matrix,以下类型的多个请求:

  • 计算其子矩形范围内元素的总和,该子矩阵的 左上角(row1, col1)右下角(row2, col2)

实现 NumMatrix 类:

  • NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初始化
  • int sumRegion(int row1, int col1, int row2, int col2) 返回 左上角 (row1, col1)右下角 (row2, col2) 所描述的子矩阵的元素 总和

image-20241025115238175

我的思路

  • 同样,使用一个int[m][n]的矩阵来记录从(0, 0)(i, j)之间的值
  • 那么从(row1, col1) -> (row2, col2)之间所有元素的和可以计算为
    • res = sum(row2, col2) - sum(row2, col2 - 1) - sum(row1 - 1, col2) + sum(row1 - 1, col1 - 1)
int[][] sumMatrix;

public T304SubMatrixSum() {

}

public T304SubMatrixSum(int[][] matrix) {
    int m = matrix.length;
    int n = matrix[0].length;

    sumMatrix = new int[m + 1][n + 1];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            sumMatrix[i + 1][j + 1] = matrix[i][j] + sumMatrix[i][j + 1] + sumMatrix[i + 1][j] - sumMatrix[i][j];
        }
    }

}

public int sumRegion(int row1, int col1, int row2, int col2) {
    return sumMatrix[row2 + 1][col2 + 1] 
        - sumMatrix[row2 + 1][col1] 
        - sumMatrix[row1][col2 + 1] 
        + sumMatrix[row1][col1];
}

时间复杂度:遍历了一遍二维数组,时间复杂度为O(M * N)

空间复杂度:额外的一个二维数组来记录subMatrix前缀和,空间复杂度为O(M * N)