前缀和

6 篇文章 0 订阅

预备知识

前缀和是一个数组的某项下标之前(包括此项元素)的所有数组元素的和。设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 到 ji ≤ j)范围内元素的总和sumRange,包含 i两点。

分析

由预备知识,我们可以求出对应的前缀和数组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)
//著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

​   

 

参考:

https://www.cnblogs.com/-Ackerman/p/11162651.html

https://leetcode-cn.com/problems/range-sum-query-2d-immutable/solution/ru-he-qiu-er-wei-de-qian-zhui-he-yi-ji-y-6c21/

https://leetcode-cn.com/problems/range-sum-query-immutable/solution/presum-qian-zhui-he-xiang-xi-jiang-jie-b-nh23/

https://leetcode-cn.com/problems/range-sum-query-immutable/solution/qu-yu-he-jian-suo-shu-zu-bu-ke-bian-by-l-px41/

https://leetcode-cn.com/problems/range-sum-query-2d-immutable/solution/dai-tu-shi-java-er-wei-qian-zhui-he-by-c-pebj/

https://leetcode-cn.com/problems/range-sum-query-2d-immutable/solution/er-wei-qu-yu-he-jian-suo-ju-zhen-bu-ke-b-2z5n/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值