前缀和算法用于快速,频繁计算一个索引区间内的元素之和。
1 一维数组中的前缀和算法
见LeetCode第303题[区域和检索-数组不可变].
题目描述
给定一个整数数组 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])
我的思路
- 每次都搜索指定区间,然后遍历区间得到元素之和,时间复杂度比较高,达到
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)所描述的子矩阵的元素 总和 。
我的思路
- 同样,使用一个
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)