首页 > 编程语言 >算法修炼之路之前缀和

算法修炼之路之前缀和

时间:2024-10-09 23:20:06浏览次数:3  
标签:hash 前缀 nums int ret 算法 vector 修炼

目录

一:一维前缀和

二:二维前缀和 

三:LeetCode OJ练习 

 1.第一题

2.第二题

 3.第三题

 4.第四题

5.第五题

6.第六题

一:一维前缀和

这里通过例题来引出

牛客_DP34 【模板】前缀和

画图分析:

具体代码:

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

int main() 
{
   //1.读入数据
   int l=0,r=0,n=0,q=0;
   cin>>n>>q;
   vector<int> arr(n+1);
   for(int i=1;i<=n;++i) cin>>arr[i];

   //2.预处理出来一个前缀和数组
   vector<long long> dp(n+1);//防止溢出
   for(int i=1;i<=n;++i)
   {
    dp[i]=dp[i-1]+arr[i];//dp[0]=0,不影响计算结果
   }

   //3.使用前缀和数组
   while(q--)
   {
    cin>>l>>r;
    cout<<dp[r]-dp[l-1]<<endl;
   }

   return 0;
}

二:二维前缀和 

 这里通过例题来引出

牛客_DP35 【模板】二维前缀和

画图分析:

具体代码:

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

int main() 
{
   //读入数据
   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];

    //预处理前缀和矩阵
    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=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;
}

三:LeetCode OJ练习 

 1.第一题

LeetCode_724 寻找数组的中心下标

画图分析:

 具体代码:

 int pivotIndex(vector<int>& nums) {
        int n=nums.size();

        //预处理前缀和数组+后缀和数组
        vector<int> f(n),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;
    }

2.第二题

LeetCode_238 除自身以外数组的乘积

画图分析:

具体代码:

vector<int> productExceptSelf(vector<int>& nums) {
        int n=nums.size();

        //1.预处理前缀积数组和后缀积数组
        vector<int> f(n),g(n);
        f[0]=g[n-1]=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> ret(n);
        for(int i=0;i<n;++i)
          ret[i]=f[i]*g[i];

        return ret;
    }

 3.第三题

LeetCode_560 和为k的子数组

 画图分析:

具体代码:

int subarraySum(vector<int>& nums, int k) 
    {
        unordered_map<int,int> hash;//统计前缀和及出现次数
        hash[0]=1;//处理特殊情况

        int sum=0,ret=0;
        for(auto e:nums)
        {
            sum+=e;//计算当前位置的前缀和
            if(hash.count(sum-k)) ret+=hash[sum-k];//统计个数
            hash[sum]++;
        }

        return ret;
    }

 4.第四题

LeetCode_974 和可被k整除的子数组

画图分析:

具体代码:

 int subarraysDivByK(vector<int>& nums, int k) 
    {
        unordered_map<int,int> hash;//统计前缀和的余数及对应个数
        hash[0%k]=1;

        int sum=0,ret=0;
        for(auto e:nums)
        {
            sum+=e;//算出当前位置的前缀和
            int r=(sum%k+k)%k;//修正后的余数
            if(hash.count(r)) ret+=hash[r];//统计结果
            hash[r]++;
        }

        return ret;
    }

5.第五题

LeetCode_525 连续数组

画图分析:

具体代码:

int findMaxLength(vector<int>& nums) 
    {
        unordered_map<int,int> hash;
        hash[0]=-1;//默认有一个前缀和为0的情况
        int sum=0,ret=0;
        for(int i=0;i<nums.size();++i)
        {
            sum+=nums[i]==0? -1:1;//计算当前位置的前缀和
            if(hash.count(sum)) ret=max(ret,i-hash[sum]);
            else hash[sum]=i;
        }

        return ret;
    }

6.第六题

OJ传送门 LeetCode_1314 矩阵区域和

画图分析: 

具体代码:

vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) 
    {
        int m=mat.size(),n=mat[0].size();
        //1.预处理一个前缀和矩阵
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        for(int i=1;i<=m;++i)
         for(int j=1;j<=n;++j)
           dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+mat[i-1][j-1];

        //2.使用
        vector<vector<int>> ret(m,vector<int>(n));
        for(int i=0;i<m;++i)
         for(int j=0;j<n;++j)
         {
            int x1=max(0,i-k)+1,y1=max(0,j-k)+1;
            int x2=min(m-1,i+k)+1,y2=min(n-1,j+k)+1;
            ret[i][j]=dp[x2][y2]-dp[x1-1][y2]-dp[x2][y1-1]+dp[x1-1][y1-1];
         }

        return ret;
    }

标签:hash,前缀,nums,int,ret,算法,vector,修炼
From: https://blog.csdn.net/Miwll/article/details/142733928

相关文章

  • 算法校赛准备
    独木桥题目背景战争已经进入到紧要时间。你是运输小队长,正在率领运输部队向前线运送物资。运输任务像做题一样的无聊。你希望找些刺激,于是命令你的士兵们到前方的一座独木桥上欣赏风景,而你留在桥下欣赏士兵们。士兵们十分愤怒,因为这座独木桥十分狭窄,只能容纳$1$个人通过。假如......
  • 代码随想录算法训练营 | 背包问题 二维,背包问题 一维,416. 分割等和子集
    背包问题二维题目链接:背包问题二维文档讲解︰代码随想录(programmercarl.com)视频讲解︰背包问题二维日期:2024-10-09想法:dp[i][j],i表示需要从物品0-i中选择加入到背包中,j表示背包的容量,dp值表示最大的价值;递推公式,如果背包大小j都比此时要放的物品i的weight[i]小了,背包放不下......
  • 代码随想录算法训练营day10| 232.用栈实现队列 225. 用队列实现栈 20. 有效的括
    学习资料:https://programmercarl.com/栈与队列理论基础.html栈与队列学习记录:232.用栈实现队列(两个栈(stack_in,stack_out)实现一个队列的行为)点击查看代码classMyQueue(object):def__init__(self):self.stack_in=[]self.stack_out=[]d......
  • codeforces round 974(div.3)E(优先队列实现dijstra算法,devc++的优先队列用greater报
    解题历程:看到两边同时移动,计算最终的相遇时间,我就想到两边同时计算各点到起点的最短距离,就是使用dijstra算法,最后所有节点取两次计算的最大值,再对所有节点取最小值,就是最终答案了,可是这个思路没有考虑有马的情况,思考一番后发现可以多列一个数组记录有马的情况下的行走最短路,然后......
  • 必知的十大计算机视觉算法
    成长路上不孤单......
  • JAVA——常见算法
    查找算法基本查找从0索引开始查找是否找到packagecom.itheima.search;importjava.security.KeyStore;publicclassBasicSearchDemo1{publicstaticvoidmain(String[]args){int[]arr={23,34,54,24,43,46};intnumber=43;......
  • 简明逻辑回归算法
     逻辑回归是一种用于分类问题的统计方法,尽管名称中包含“回归”,但它主要用于二分类任务。为了更好地理解逻辑回归,我们可以通过一个通俗易懂的例子来解释。例子:判断是否通过考试假设你是一名老师,想要根据学生的学习时间来判断他们是否能通过一次考试。我们将“通过考试”定义为......
  • DAY27||回溯算法基础 | 77.组合| 216.组合总和Ⅲ | 17.电话号码的字母组合
    回溯算法基础知识一种效率不高的暴力搜索法。本质是穷举。有些问题能穷举出来就不错了。回溯算法解决的问题有:组合问题:N个数里面按一定规则找出k个数的集合切割问题:一个字符串按一定规则有几种切割方式子集问题:一个N个数的集合里有多少符合条件的子集排列问题:N个数按一定规......
  • 不同的快排算法
    之前写过一篇快排但是现在来看写的很简单,很无聊 快排的思想其实大家都懂这次详细写写不同快排之间的区别和一些优化点 1.首先是pivot元素的选择a.当我们数组本身就是随机的时候,选择第一个/最后一个/中间一个都是可以的,但如果数组是有某种规律的,有可能会退化......
  • 合并、删除区间算法C++代码
    #include<algorithm>#include<iostream>#include<vector>usingnamespacestd;classSolution{public:constintCOMBINE_INT=0;//1表示整数点区间,比如[1:3]和[4:5]会合并为[1:5],0则仅会合并[1:3]和[3:4]这类的区间。vector<pair<int,int>>......