预备知识
前缀和是一个数组的某项下标之前(包括此项元素)的所有数组元素的和。设a[]为原数组,b[]为前缀和数组,可得,前缀和的定义式和递推式如下图所示:
其中,一维数组的前缀和的递推式可以很容易看出来,二维数组的前缀和的递推式证明如下:
如图,灰色阴影的面积 S(O,D)=S(O,C)+S(O,B)−S(O,A)+D。设preSum[i][j]表示从matrix[0][0]到matrix[i][j]的所有元素的和,则可以得出以下的递推公式:
preSum[i][j]=preSum[i−1][j]+preSum[i][j−1]−preSum[i−1][j−1]+matrix[i][j]
求数组中部分元素之和
题目:给定一个整数数组 nums
,求出数组从索引 i
到 j
(i ≤ j
)范围内元素的总和sumRange,包含 i
、j
两点。
分析:
由预备知识,我们可以求出对应的前缀和数组preSum, 因此可以很容易得出
sumRange(i,j) = preSum[j] - preSum[i-1]
优化技巧:
上式中,需要对i = 0的情况做特殊处理。因此,定义长度为n+1的preSum数组,preSum[i]表示该元素左边所有元素之和(不包括i元素)(另一种理解方法:可以认为preSum数组是在nums数组之前补了一个0,因此nums中第j个元素,对应preSum中第j+1个元素),则
preSum[i] = nums[0,i-1)
preSum[i+1] = nums[0, i) = preSum[i]+nums[i]
sumRange(i,j) = preSum[j+1] - preSum[i]
typedef struct {
int* sums;
} NumArray;
NumArray* numArrayCreate(int* nums, int numsSize) {
NumArray* ret = malloc(sizeof(NumArray));
ret->sums = malloc(sizeof(int) * (numsSize + 1));
ret->sums[0] = 0;
for (int i = 0; i < numsSize; i++) {
ret->sums[i + 1] = ret->sums[i] + nums[i];
}
return ret;
}
int numArraySumRange(NumArray* obj, int i, int j) {
return obj->sums[j + 1] - obj->sums[i];
}
void numArrayFree(NumArray* obj) {
free(obj->sums);
}
求二维矩阵中的子矩阵元素之和
题目:
分析:
由预备知识,可以用前缀和公式算出任意子矩阵的面积,如下图,S(A,D)=S(O,D)−S(O,E)−S(O,F)+S(O,G)
设A = (row1, col1), D = (row2, col2),则
sumRegion() = preSum[row2][col2]−preSum[row2][col1−1]−preSum[row1−1][col2]+preSum[row1−1][col1−1]
优化技巧:
上式需要额外判断行列参数等于0的情况,因此,设前缀和数组preSum[row+1][col+1],相当于在原数组前增加了一行一列:
因此,原数组中(col,row)对应preSum中的(col+1, row+1)
所以 sumRegion() = preSum[row2][col2]−preSum[row2][col1−1]−preSum[row1−1][col2]+preSum[row1−1][col1−1]
= preSum[row2+1][col2+1]−preSum[row2+1][col1]−preSum[row1][col2+1]+preSum[row1][col1]
typedef struct {
int** sums;
int sumsSize;
} NumMatrix;
NumMatrix* numMatrixCreate(int** matrix, int matrixSize, int* matrixColSize) {
NumMatrix* ret = malloc(sizeof(NumMatrix));
ret->sums = malloc(sizeof(int*) * (matrixSize + 1));
ret->sumsSize = matrixSize + 1;
int n = matrixSize ? matrixColSize[0] : 0;
for (int i = 0; i <= matrixSize; i++) {
ret->sums[i] = malloc(sizeof(int) * (n + 1));
memset(ret->sums[i], 0, sizeof(int) * (n + 1));
}
for (int i = 0; i < matrixSize; i++) {
for (int j = 0; j < matrixColSize[i]; j++) {
ret->sums[i + 1][j + 1] = ret->sums[i][j + 1] + ret->sums[i + 1][j] - ret->sums[i][j] + matrix[i][j];
}
}
return ret;
}
int numMatrixSumRegion(NumMatrix* obj, int row1, int col1, int row2, int col2) {
return obj->sums[row2 + 1][col2 + 1] - obj->sums[row1][col2 + 1] - obj->sums[row2 + 1][col1] + obj->sums[row1][col1];
}
void numMatrixFree(NumMatrix* obj) {
for (int i = 0; i < obj->sumsSize; i++) {
free(obj->sums[i]);
}
free(obj->sums);
}
//作者:LeetCode-Solution
//链接:https://leetcode-cn.com/problems/range-sum-query-2d-immutable/solution/er-wei-qu-//yu-he-jian-suo-ju-zhen-bu-ke-b-2z5n/
//来源:力扣(LeetCode)
//著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
参考: