前缀和系列

001 DP34 【模板】前缀和

题目描述

在这里插入图片描述
题目链接

解题思路

在这里插入图片描述
在这里插入图片描述

代码实现

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

int main() {
    //1、读取数据
    int n = 0, q = 0;
    cin >> n >> q;
    vector<int> arr(n+1, 0);
    for(int i = 1; i <= n; ++i)
    {
        cin >> arr[i];
    }

    //2、预处理出前缀和数组
    vector<long long> dp(n+1, 0);  //long long防止求和时溢出
    for(int i = 1; i <=n; ++i)
    {
        dp[i] = dp[i-1] + arr[i];
    }

    //3、使用前缀和数组求解
    int l = 0, r = 0;
    while(q--)
    {
        cin >> l >> r;
        cout << dp[r] - dp[l-1] << endl;
    }
    return 0;
}


002 DP35 【模板】二维前缀和

题目描述

在这里插入图片描述
题目链接

解题思路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码实现

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

int main() {
    //1、读入数据
    int n = 0, m = 0, q = 0;
    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];
        }
    }

    //2、预处理得到前缀矩阵
    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];
        }
    }

    //3、利用前缀矩阵计算结果
    int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
    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;
}
// 64 位输出请用 printf("%lld")

003 寻找数组的中心下标

题目描述

在这里插入图片描述

题目链接

解题思路

在这里插入图片描述
在这里插入图片描述

代码实现

// class Solution {
// public:
//     int pivotIndex(vector<int>& nums) {
//         //优化
//         if(nums.size() == 1) return 0;

//         int n = nums.size();
//         int tmp = 0;
//         //定义预处理数组1,2
//         //dp1,dp2开n+2个大小,为了防止左右边界越界
//         vector<int> dp1(n + 2,0);
//         for(int i = 0; i < n; ++i)
//         {
//             dp1[i + 1] = nums[i] + dp1[i];
//         }

//         vector<int> dp2(n + 2,0);
//         for(int i = n-1; i >= 0; --i)
//         {
//             dp2[i + 1] = nums[i] + dp2[i + 2];
//         }

//         //利用预处理数组求解结果
//         int dest = 2;
//         for(int cur = 1; cur <= n; )
//         {
//             if(dp1[cur - 1] == dp2[dest]) return cur - 1;
//             ++dest;
//             ++cur;
//         }
//         return -1;
//     }
// };

class Solution {
public:
    int pivotIndex(vector<int>& nums) {
        int n = nums.size();

        //1、预处理前缀和和后缀和数组
        //Notice:f[i]:表示nums数组中【0,i-1】区间内所有元素之和
        vector<int> f(n, 0), g(n, 0);
        for(int i = 1; i <= n-1; ++i)
        {
            f[i] = f[i-1] + nums[i-1];
        }

        //Notice:g[i]:表示nums数组中【i+1,n-1】区间内所有元素之和
        for(int i = n-2 ; i >=0 ; --i)
        {
            g[i] = g[i+1] + nums[i+1];
        }

        //2、利用预处理后的数组计算最终结果
        for(int i = 0; i < n; ++i)
        {
            if(f[i] == g[i]) return i;
        }
        return -1;
      
    }
};

004 除自生以外数组的乘积

题目描述

在这里插入图片描述

题目链接

解题思路

在这里插入图片描述

代码实现

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n = nums.size();

        //1、预处理前缀积和后缀积
        vector<int> f(n, 1), g(n, 1);
        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];
        }

        //2、利用前缀积和后缀积计算最终结果
        vector<int> answer;
        for(int i = 0; i < n; ++i)
        {
            answer.push_back(f[i]*g[i]);
        }
        return answer;
    }
};

005 和为k的子数组

题目描述

在这里插入图片描述

题目链接

解题思路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码实现

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> hash; //统计前缀和出现的次数
       
        //数组中和为k的子数组个数-> 数组中[0,i]区间内,有多少个前缀个等于sum[i] - k
        int sum = 0;
        int ret = 0;
        hash[0] = 1;
        for(auto e : nums)
        {
            sum += e;   //计算前缀和
            if(hash.count(sum - k)) ret += hash[sum - k];   //统计前缀个等于sum[i] - k的个数
            hash[sum]++;    //将前缀和加入到hash表
        }
        return ret;
    }
};

 

006 和可被k整除的子数组

题目描述

在这里插入图片描述
题目链接

解题思路

在这里插入图片描述
在这里插入图片描述

代码实现

class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k) {
        unordered_map<int, int> hash;

        //nums中元素之和可被k整除的非空子数目的数目->
        //在[0, i - 1]区间内,计算有多少前缀和除以k的余数(即前缀和 % k)
        //等于(sum % k + k) % k
        int ret = 0;
        int sum = 0;
        hash[0 % k] = 1;   //0这个数的余数
        for(auto e : nums)
        {
            sum += e;  //计算前缀和
            int r = (sum % k + k) % k;  //修正后的余数

            //统计hash表中有多少前缀和除以k的修正后的余数(即前缀和 % k)
            //等于(sum % k + k) % k
            if(hash.count(r)) ret += hash[r];  
            hash[r]++;
        }

        return ret;
    }
};

 

007 连续数组

题目描述

在这里插入图片描述
题目链接

解题思路

在这里插入图片描述
在这里插入图片描述

代码实现

class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        unordered_map<int, int> hash;  //用于统计区间下标

        int sum = 0;
        int ret = 0;
        hash[0] = -1;  //前缀和为0时,所对应的索引为-1;
        for(int i = 0; i < nums.size(); ++i)
        {
            sum = sum + (nums[i] == 0? -1 : 1); //将0->-1, 计算前缀和
            //检查hash表中,在[0, i-1]区间中,是否存以i位置为结尾的前缀和为sum;
            //若存在,则计算区间
            if(hash.count(sum)) 
                ret = max(ret, i - hash[sum]);
            else 
                hash[sum] = i;  //hash表中不存在前缀和时,才将前缀和和索引,
                                //保存到hash表中,相同得前缀和,我们保存的是前一个
        }
        return ret;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值