“前缀和”专题篇一

目录

【模版】前缀和

【模版】二维前缀和

寻找数组的中心下标

除自身以外数组的乘积


【模版】前缀和

题目

思路

这道题如果使用暴力解法,即针对每次查询,先算出前r个数的总和,然后再算出前l-1个数的总和,然后相减就得出本次查询的结果,但是这样的话,时间复杂度是O(N*Q),会超时,因此需要别的方法来解决。

下面使用“前缀和”来解决这道题,即先算出每个位置(含该位置)之前所有数的总和,使用一个数组存储起来,然后针对每次查询就可以使用O(1)的时间复杂度得到结果。

代码

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n,q;
    cin>>n>>q;
    vector<int> arr(n+1);
    for(int i=1;i<=n;i++)
        cin>>arr[i];
    vector<long long> dp(n+1);
    for(int i=1;i<=n;i++)
        dp[i]=dp[i-1]+arr[i];
    int l,r;
    while(q--){
        cin>>l>>r;
        cout<<dp[r]-dp[l-1]<<endl;
    }
    return 0;
}
【模版】二维前缀和

题目

思路

这道题如果使用暴力解法的话,即针对针对查询,算出本次查询的区域,然后再计算出该区域所有数的和,但是这种方法的时间复杂度是O(N*M*Q),是会超时的,因此需要别的方法来解决。

下面将依旧使用“前缀和”的思想来解决这道题,即预先计算出每个位置和左上角构成的矩形的值的总和,针对每次查询,就可以使用O(1)的时间复杂度计算出所查询区域的值的总和。

【1】计算好每个位置和左上角构成的矩形的值的总和

【2】计算出所查询区域的值的总和

代码

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n,m,q;
    cin>>n>>m>>q;
    vector<vector<int>> arr(n+1,vector<int>(m+1));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>arr[i][j];
    vector<vector<long long>> dp(n+1,vector<long long>(m+1));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            dp[i][j]=dp[i-1][j]+dp[i][j-1]+arr[i][j]-dp[i-1][j-1];
    int x1,y1,x2,y2;
    while(q--){
        cin>>x1>>y1>>x2>>y2;
        cout<<dp[x2][y2]-dp[x1-1][y2]-dp[x2][y1-1]+dp[x1-1][y1-1]<<endl;
    }
    return 0;
}
寻找数组的中心下标

题目

思路

使用“前缀和”来解决这道题,不过要计算一个前缀和数组f和一个后缀和数组g,前缀和数组f[i]表示当前位置之前所有元素的和,后缀和数组g[i]表示当前位置之后所有元素的和,然后遍历每个位置,看该位置的前缀和和当前位置的后缀和是否相等。

代码

class Solution {
public:
    int pivotIndex(vector<int>& nums) {
        int n=nums.size();
        vector<int> f(n);
        vector<int> g(n);
        for(int i=1;i<n;i++)
            f[i]=f[i-1]+nums[i-1];
        for(int i=n-2;i>=0;i--)
            g[i]=g[i+1]+nums[i+1];
        for(int i=0;i<n;i++)
            if(f[i]==g[i]) return i;
        return -1;
    }
};
除自身以外数组的乘积

题目

思路 

解决这道题使用类似于“前缀和”思想的“前缀积”和“后缀积”,使用数组f计算从开始位置到当前位置之前所有元素的乘积,使用数组g计算从末尾到当前位置的下一个位置的乘积,分别计算该位置之前所有元素的乘积以及该位置之后所有元素的乘积,然后遍历整个数组,计算出每个位置除自身以外数组的乘积。

代码

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n=nums.size();
        vector<int> f(n);
        vector<int> g(n);
        f[0]=g[n-1]=1;
        vector<int> ret(n);
        for(int i=1;i<n;i++)
            f[i]=f[i-1]*nums[i-1];
        for(int i=n-2;i>=0;i--)
            g[i]=g[i+1]*nums[i+1];
        for(int i=0;i<n;i++)
            ret[i]=f[i]*g[i];
        return ret;
    }
};

  • 91
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 103
    评论
评论 103
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新绿MEHO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值