活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 一键部署Llama3大模型学习机 0代码一键部署,预装最新主流大模型Llama3与StableDiffusion
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 产品能力
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      首页 知识中心 软件开发 文章详情页

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      2025-05-06 09:19:39 阅读次数:1

      dp,前缀,数组,矩阵,题目

      前缀和算法总结:

      常规的前缀和分为两种(也是练习1、2):

      1. 一维前缀和:比较简单,在我们需要快速的算出某一数组中的数据时,可以想想是否能使用前缀和,它的使用条件:

        1. 一维数组
        2. 求数组中任意连续的值
        • 对于满足上述条件后就能考虑使用前缀和数组
        • 其中前缀和数组存储dp[ i ]的是:从 1~ i 区域内的元素值之和
        • 其中下标从1开始算,每次创建的数组大小为 n + 1 保证从 1 开始(从1开始是因为: 计算 dp[i] 需要使用 dp[i - 1],假设 i 不从1开始,若 i 为0,就会越界访问)
        • 具体当我们拥有了一个前缀和数组dp后,使用前缀和数组算出结果,当要求 r ~ l这段区间时它的计算方法就是: dp[ r ] - dp[ l -1 ]
          【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      2. 二维前缀和:

        1. 条件类似:二维数组,当要求某一块区间的值时 可以考虑使用二维前缀和

        2. 该二维前缀和数组dp[ i ][ j ]中存储的是:从 (0,0) ~ (i,j)区域的所有元素值的和
          【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

        3. 使用:对于二维前缀和的使用稍微对比起来有点难度,一般来说需要使用到两个公式

          1. 计算出二维前缀和数组中的值的公式:dp[ i ][ j ] = dp[ i ][ j - 1] + dp[ i-1 ][ j ] + arr[ i ][ j ] - dp[ i - 1 ][ j - 1 ]

          对于该公式,切记一定不要死记
          通过下图右边图记忆:
          理解:当我们我们要求的空间可以分为右边图形中的四块:A、B、C、D,其中假如我们从上往下,从左往右的去填写当前的dp数组时,本质上 A、B、C三个区域的值都是已经算好了的,而对于 D 来说他就是自身当前位置的值 arr[ i ][ j ],所以这样我们就能得出上面的公式:
          A = dp[ i - 1][ j - 1 ]、B = dp[ i - 1][ j ]、C = dp[ i ][ j - 1 ]、D = arr[ i ][ j ]
          【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

          1. 使用二维前缀和公式快速算出任意两点(x1,y1) ~ (x2,y2)区域的公式:dp[ x2 ][ y2 ] - dp[ x1 - 1 ][ y2 ] - dp[ x2 ][ y1 - 1 ] - dp[ x2 ][ y1 - 1] + dp[ x1 - 1][ y1 - 1 ]

          而对于这个公式来说同样,也是通过一张图进行记忆:
          具体如下就过诉了,这里本质要求的就是 D 区域,如何通过 提前准备好的 二维前缀和数组 求出 D区域的值(同样还是记忆下面右图逻辑即可,必要时画个图)
          【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      3. 其中前缀和只是个思想,它使用一个数组的形式提前存储一段区间的值,其中这个 区间的值的求法,可能并不一样

        1. 比如存储了 1 ~ i 区间的和、
        2. 存储了 1 ~ i 区间的乘积、
        3. 存储了 1 ~ i 区间的某个数的出现个数…
        4. 再或者是一个后缀和(从后往前的记录其中的值)
      • 始终记住前缀和可以用来求出某一段连续区域的值的思想,后面首先会通过两道简单的题(一维和二维前缀和练手),后面将会逐步递增难度(也就代表这个前缀和中存储的并不是 前缀的和)
      • 过程中一般都是求某段连续区域中的某个值,对于感觉大脑不够想的时候一定要画图!通过简单的图示更方便的理解和写出公式

      具体训练:

      1. 一维前缀和【模板】

      题目:

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      分析题目并提出,解决方法:

      结合题目分析:

      1. 首行是 n :数组个数、q:查询次数
      2. 第二行是有n个元素的数组的值:…
      3. 后面有q行,它的值代表查找区间 [左 ~ 右]
      4. 那么然后输出查询结果
      5. 例如在下面 1 2 4 数组中查找(1,2)、(2,3)、(1,3) 区间的值,具体如下
        【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
        暴力题解:简单的模拟,根据给q次给的left、right下标,并从该区间【left,right】遍历求和得出答案(O(n * q)的时间复杂度)

      对于这种连续数组中求和的情况我们一定要想到前缀和:快速求出数组中某一个连续区间的和
      前缀和算法到底是什么?
      通过实例来解释:

      一维前缀和模板:

      1. 预处理出来一个前缀和数组dp(小动态规划)
        1. dp[i]:表示的是 1 ~ i 区间所有元素的和(下标从1开始算,每次创建的数组大小为 n + 1 保证从 1 开始)
          【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
        2. 并且在计算dp数组的过程中,==dp[ i ] = dp[ i - 1] + arr[ i ]==即可算出(具体分析如上图很好理解),这样更快的求出,不需要每次都遍历真个数组!
        3. 为什么下标从1开始:因为此处要计算 dp[i] 需要使用 dp[i - 1],i 若为0,就会越界,所以从1开始,这样 即使第一个情况下:1 - 1 = 0 也不会越界
      2. 使用前缀和数组
        1. 当我们得到一个前缀和数组后,假设有下情况:
          【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
        2. 当我们要去 l ~ r 情况的值:就能通过快速的减法得到:dp[ r ] - dp[ l -1 ]
        3. 算法时间复杂度:O(n) + O(q) = O(n)

      题解核心逻辑:

      1. 根据题目初始化存储好:n,q,数组,查询区域
      2. 初始化前缀和数组dp
        1. dp[ i ] = dp[ i - 1] + arr[ i ]
      3. 使用前缀和数组算出结果
        1. dp[ r ] - dp[ l -1 ]

      代码:

      #include <iostream>
      #include <vector>
      using namespace std;
      
      int main() {
          int n  , q;
          cin >> n >> q;
          long long arr[100010] = {0};//根据题目数量级设置,之前设置超过数量级大小的数组即可
          long long dp[100010] = {0};
          for(int i = 1; i <= n;i++){//从1开始因为,前缀和需要下标从1开始,留0位置
              cin >> arr[i];
          }
          vector<vector<long long>> lr;//使用vector存储左右区间
          lr.resize(q);
          for(int i = 0 ; i < q;i++){
              int left,right;
              cin >> left >> right;
              lr[i].push_back(left);
              lr[i].push_back(right);
          }
      
          //1. 使用一维前缀和快速求值:
          //dp[i] = arr[i] + dp[i-1]
          for(int i = 1; i <= n;i++){
              dp[i] = arr[i] + dp[i-1];
          }
      
          for(int i = 0 ; i < q;i++){
              // 使用前缀和求值
              int l = lr[i][0];
              int r = lr[i][1];
              cout << dp[r] - dp[l-1] << endl; 
          }
          return 0;
      }
      

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      2. 二维前缀和【模板】

      题目:

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      分析题目并提出,解决方法:

      分析题目的例子并理解:

      1. 第一行是三个数n,m,q
      2. n:代表矩阵数据的行数,m代表矩阵列数,q代表请求查询的参数
      3. 其次n行m列的数就是矩阵数据
      4. 最后的q行数据代表的是:查询的矩阵的左上角和右下角两点,
      5. 过程中可以将数据看成每两个为一个矩阵中的xy点,这样就能得到两点(x1,y1)、(x2,y2)
        如下数据的第一个查询参数值是 1 1 2 2 那么查询的的两点是 (1,1) ~ (2,2)

      最终要求的就是这两点矩阵区间的值(如下图)

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      暴力解法:同样是模拟,根据给的两点的确定查询的矩阵的行列,遍历求和即可

      二维前缀和模板:

      1. 预处理处一个前缀和矩阵

        1. 创建和原处理矩阵同等大小矩阵dp
        2. 然后对dp中的值进行设置,此处dp内的值和一维前缀和里的值略有不同也更难理解一丢丢,此处二维的是求从 (1,1) ~ (i, i)内这个小矩阵的和,但直接求发现还是表还是得遍历时间复杂度还是比较高,那么在求的过程中就能不能优化下?可以通过利用之前的dp矩阵得出快速求dp[ i ][ j ] = dp[ i ][ j - 1] + dp[ i-1 ][ j ] + arr[ i ][ j ] - dp[ i - 1 ][ j - 1 ]
          具体如下图(注意记住左下角那张分析图,能很好的帮助你理解和记忆公式):
          【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      2. 如何使用前缀和矩阵快速取出要求的指定矩阵中的值

        1. 方法类似通过对原矩阵进行分割,通过许多前面算好的矩阵中的值来快速的计算出当前的值,其中划分的步骤很关键,一定要好好理解。
        2. 为什么划分,为了利用之前的值,并且在划分的过程中使用了更简洁的图来更方便理解!
        3. 那么如何使用求出指定的区域能,如下图求D区域,找到左下角点和右下角点,分析该如何划分区间,本质就是要考虑两点的关系
        4. 首先我们可以记住若左上角刚好在整个矩阵的左上角,那么要求的值就是d[x2][y2]的区间的大小
        5. 那么当左上角不在整个原矩阵最左上角时,对于右下角的值来说需要将左上角之外的多余的值给清除(这样记忆更加的好通过图来记忆公式!)

      最终划分出来后如下图(注意记住好左边那张分析图,通过这理解这张图帮助你快速理解和记忆公式)
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      5.最终得出的所要求的区域值就是: dp[ x2 ][ y2 ] - dp[ x1 - 1 ][ y2 ] - dp[ x2 ][ y1 - 1 ] - dp[ x2 ][ y1 - 1] + dp[ x1 - 1][ y1 - 1 ]

      题解核心逻辑:

      1. 根据题目初始化存储好:n,m,q、矩阵,查询的两点
      2. 初始化前缀和矩阵dp
        1. dp[ i ][ j ] = dp[ i ][ j - 1] + dp[ i-1 ][ j ] + arr[ i ][ j ] - dp[ i - 1 ][ j - 1 ]
      3. 使用前缀和数组算出结果
        1. dp[ x2 ][ y2 ] - dp[ x1 - 1 ][ y2 ] - dp[ x2 ][ y1 - 1 ] - dp[ x2 ][ y1 - 1] + dp[ x1 - 1][ y1 - 1 ]

      代码:

      #include <iostream>
      using namespace std;
      #include <vector>
      
      int main() {
          int n, m, q;
          cin >> n >> m >> q;
          long long arr[1010][1010] = {0};
          long long dp[1010][1010] = {0};
          for (int i = 1; i <= n;
                  i++) { //从1开始因为,前缀和需要下标从1开始,留0位置
              for (int j = 1; j <= m; j++) {
                  cin >> arr[i][j];
              }
          }
          vector<vector<long long>> lr;//使用vector存储左右区间
          lr.resize(q);
          for (int i = 0 ; i < q; i++) {
              int x1, y1, x2, y2;
              cin >> x1 >> y1 >> x2 >> y2;
              lr[i] = {x1, y1, x2, y2}; //使用initiate
          }
      
          //初始化dp值
          for (int i = 1; i <= n;
                  i++) { //从1开始因为,前缀和需要下标从1开始,留0位置
              for (int j = 1; j <= m; j++) {
                  dp[i][j] = arr[i][j] + dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1];
                  // dp[i][j] = A + B + C + D =  D + (A + B) + (A + C)- A
              }
          }
      
      
          //使用dp值:
          for (int i = 0 ; i < q; i++) {
              int x1 = lr[i][0], y1 = lr[i][1], x2 = lr[i][2], y2 = lr[i][3];
              cout << dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1] << endl;
              // D = (x2y2) - B - C - A = (x2y2) - (A+B) - (A+c) + A 
          }
      
          return 0;
      }
      // 64 位输出请用 printf("%lld")
      

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      3. 寻找数组的中心下标

      题目:

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      分析题目并提出,解决方法:

      分析题目,不难理解示题1的3结果由来:
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      两种特殊情况:
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      1. 当没有结果时返回 -1
      2. 默认最左边元素的左半区为0,最右边元素的右边区也为0
      3. 并且当结果有多个的时候返回最左边的结果

      本质所要求的是如下图( i 的左边区间 = i 的右边区间的 i ):
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      本题本质还是在连续数组中找值,那么我们就能使用前缀和思想:

      1. 提前预处理好数据到dp中
        1. 现在需要求的就是 ( 0,i - 1 )、( i + 1,n -1) 这两区间的值
          【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
        2. 前缀和数组:f [ i ] = f [ i - 1 ] + num [ i - 1 ]
        3. 后缀和数组: g [ j ] = g [ i + 1 ] + num[ i + 1 ]
      2. 利用提前处理好的数组,进行题目要求的判断
        1. 假设要判断 i 位置的点是否符合条件 那么就等于判断 f[ i ] == g[ i ]

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      题解核心逻辑:

      1. 创建前缀和数组f:0 ~ i -1、后缀和数组g:i + 1 ~ n - 1
      2. 通过前面的公式预处理
        1. f[ i ] = f[ i - 1 ] + arr[ i - 1 ]
        2. g[ i ] = g[ i + 1 ] + arr [ i + 1]
      3. 最后遍历数组,找到f[ i ] == g[ i ]处

      更多细节见具体代码:

      class Solution {
      public:
      
          static const int CAP = 1e4 + 10;
          int pivotIndex(vector<int>& nums) {
              //分析出本题:本质可以通过提前预处理好数组的值来快速计算:前缀和思想
      
              //使用前缀和f数组 和 后缀和g数组 存储连续数组的数据
              int f[CAP] = {0};int g[CAP] = {0};
      
              int n = nums.size();
      
              //1. 预处理数组
              //前缀和,f[i] =  0 ~ i - 1
              for(int i = 1; i <= n;i++){
                  f[i] = f[i-1] + nums[i - 1];//算出 0 ~ i - 1的和
              }
              //后缀和,g[i] = i + 1 ~ n - 1
              for(int i = n - 2;i >= 0;i--){
                  g[i] = g[i+1] + nums[i+1];//g [i] 存储的是 i + 1 ~ n - 1的值
                  //所以当 i = n - 2 存储的就是 n - 1 ~ n - 1的值
              }
      
              //2. 使用预处理数组进行判断
              for(int i = 0; i < n ;i++)
                  if(f[i] == g[i]) return i;
      
              return -1;
          }
      };
      

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      4. 除自身以外数组的乘积

      题目:

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      分析题目提出解决方法:

      本题本质其实和上一题一样,只不过,本题并不是前缀和,而是前/后 缀积
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      前缀积、后缀积的算法:
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      本质也就是将 加法 变成了 乘法(具体如下)
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      题解核心逻辑:

      基本同上就略了

      class Solution {
      public:
          static const int CAP = 100010;
          vector<int> productExceptSelf(vector<int>& nums) {
              int f[CAP] = {1};//这里是乘法所以等于1
              int g[CAP];
              int n = nums.size();
              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];
              }
      
      //使用预处理好的数组:
              vector<int> ans(n);
              for(int i = 0; i < n ;i++){
                  ans.push_back(g[i] * f[i]);
              }
              return ans;
          }
      };
      
      

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      5. 和为 K 的子数组

      题目:

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      分析题目提出解决方法:

      通过例子分析,题目的目的:
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      暴力解法,就是枚举所有情况(复杂度O(N2))

      分析如何快速找到连续子数组中的值为 k 的子数组

      1. 先画一个简单的图来分析:不难发现,若要找以 i 结尾的连续子数组,本质是在 0 ~ i - 1 这个区间找一个值为 sum[ i ] - k 的值有多少个
        (具体如下图,找k长度的区间,可以转换为找sum[ i ] - k 区间的个数,这样就和前面关联了)
        【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      2. 那如何快速的找出 0 ~ i - 1 区间中 sum[ i ] - k 的个数呢?对于这种数值的查找,可以通过hash表提前存储好

      3. 具体hash的使用是:每当查找完一个区间后,将当前下标的 sum[ i ] - k 的值存入hash中

      4. 特殊处理:当 sum[ i ] == k 时,查找的区间就是 0 ~ -1 中找 0(sum[i] - k)这本质是不存在的,所以需要提前将hash[0] = 1,因为区间不存在就无法查找,而此时 sum - k = 0,所以就代表自己这个区间就是符合条件的。

      5. 其他细节如下:
        【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      题解核心逻辑:

      1. 使用hash表不断记录 0 ~ i - 1 区间中所有sum的情况(因为通过前面的sum情况知道有多少数据为 sum[i] - k)
      2. 开始遍历数组,判断是否有值等于当前的 sum - k,若有则代表有符合长度的以i结尾的子数组然后记录个数即可
      class Solution {
      public:
          int subarraySum(vector<int>& nums, int k) {
              //存储 0 ~ i - 1 的sum[i] - k个数(注意这本质存的还是0 ~ i - 1区间中每个元素的sum,只是为了找某个值的 sum = 当前sum - k )
              unordered_map<int,int> hash;
              hash[0] = 1;//特殊处理
              int count = 0,sum = 0;
              for(int i = 0;i < nums.size();i++){
                  sum += nums[i];//
                  if(hash.count(sum - k))
                      count += hash[sum - k];
                  hash[sum]++;
              }
              return count;
          }
      };
      

      在本题中同样用到了,前缀和的思想,其中加上了hash来代替前缀和,通过hash代替前缀和中记录前面子数组值,从而实现即记录了子数组的值,右记录了相同子数组值的个数
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      6. 和可被 K 整除的子数组

      题目:

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      分析题目提出解决方法:

      本题和上题类似,本题求的是连续子数组和能被k整除个数(上题是找等于k的个数)
      直接本题通过例就能看懂了,并且暴力解法也和上类似就不过诉了!

      同余定理

      同余定理:通过公式理解(具体如下)(a - b) / p = k (余0) -> a % p = b % p
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      证明过程…:
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      c++ / java 的负数取模的结果以及修正

      1. 负数 % 正数 = 负数 -> 修改为正数:
      2. 将值a =(a % p + p)% p(这个公式保证了值无论是 整数还是负数最终都能变成正确取余后的整数)

      题解核心逻辑:

      同上题一样将数组抽象:
      若要再0 ~ i - 1区域中查找一个以i结尾的子数组的和的余数 = 0 的子数组个数
      得到下图左边的公式:(sum - x) % k = 0
      其中就要使用到同余定理得到:sum % k = x % k(从而得到了 x 区域的求法!:sum % k)
      所以本题在上题的基础上修改hash中存储的值:存储的就是所有前缀和的余数的个数
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      • hash[0] = 1;这里处理的是:当 0 ~ i 区间刚好整除 k,那么 此时 sum % k = 0
      class Solution {
      public:
          int subarraysDivByK(vector<int>& nums, int k) {
              unordered_map<int,int> hash;//一个变化的hash:存储 0 ~ i-1 内所有前缀和的余数的个数
              hash[0] = 1;//这里处理的是:当 0 ~ i 区间刚好整除 k,那么 此时 sum % k = 0
              int count1 = 0,sum = 0;
              for(int i = 0; i < nums.size();i++){
                  sum += nums[i];//前缀和
                  // cout << sum << " " << sum % k << " ";
                  if(hash.count((sum % k + k) % k))
                      count1 += hash[(sum % k + k) % k];//查找 sum % k的个数
                  // cout << hash[sum % k] << " "<< count1 << endl;
                  
                  hash[(sum % k + k) % k]++;//添加 / 创建 sum % k的个数 
              }
              return count1;
          }
      };
      

      7. 连续数组

      题目:

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      分析题目提出解决方法:

      本题关键:将 0 看出 -1
      相信如果从上往下做到了该题,那么你已经具备了一定能力了,下面我就不过多叙述; ,还是那句话遇到难题一定要画图分析
      具体分析如下图:
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      题解核心逻辑:

      class Solution {
      public:
          int findMaxLength(vector<int>& nums) {
              //将 0 看出 -1 
              //求连续子数组中和为0的个数
              unordered_map<int,int> hash;//存储前缀和的值和下标
      
      
      // 0 ~ i  sum
      // k = 0, 找前缀和等于 sum - 0 = sum 的个数
              hash[0] = -1;//此处特殊处理:当 0 ~ i 区间为0的情况下 sum就为0,那么查找的区间是不存在的,所以需要提前设置
              int sum = 0,count =0;
              int maxlen = 0;
              for(int i = 0; i < nums.size();i++){
                  sum += (nums[i] == 1 ? 1 : -1);
                  // hash[sum] 
      
                  if(hash.count(sum)){
                      // cout << sum << " " << hash.count(sum) << " " << hash[sum] <<" ";
                      maxlen = max(maxlen,i - hash[sum]);
                  }
      
                  if(!hash.count(sum)){//判断是否已经存在,若已经存在则不用再记录了,因为最左区间已经确定
                      hash[sum] = i;
                      // cout << sum << " " <<  hash[sum]<<endl;
                  }
              }
              return maxlen;
          }
      };
      

      8. 矩阵区域和

      题目:

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      分析题目提出解决方法:

      一道二维前缀和的题,理解公式轻松解决
      其中注意理解题意:本质就是求以(i,j)为中心的九宫格
      分析图如下:

      1. 其中注意 dp 的下标是从 1 开始的,所以mat中下标都要-1
        【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      2. 二维前缀和模板
        【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      3. 而 ans中的小标是从0开始的,所以使用dp时要+1

      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)
      4. 注意越界问题
      【C/C++算法】从浅到深学习--- 前缀和算法(图文兼备 + 源码详解)

      题解核心逻辑:

      class Solution {
      public:
          vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
              //很清楚的二维前缀和
              int m = mat.size();
              int n = mat[0].size(); 
      
              vector<vector<int>> ans(m,vector<int>(n,0));
      
              //创建dp表,并预处理得到所有 从 (0,0) ~ (i,j) 区域的和
              int dp[110][110] = {0};
              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];
                      cout << dp[i][j] << " ";
                  }
                  cout <<endl;
              }
      
              
              //最终通过dp表快速的求出所需要的值
              for(int i = 0; i < m;i++){
                  for(int j = 0; j < n ;j++){
                      int x1 = max(0,i - k) + 1;
                      int y1 = max(0,j - k) + 1;
                      int x2 = min(m-1,i + k) + 1;
                      int y2 = min(n-1,j + k) + 1;
      
                      // 求 (x1,y1) ~ (x2,y2) 区域的值给到ans即可
                      ans[i][j] = dp[x2][y2] - dp[x2][y1-1] - dp[x1-1][y2] + dp[x1-1][y1-1];
                      cout << ans[i][j] << " ";
                  }
                  cout << endl;
              }
              return ans;
          }
      };
      
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://z-y-k.blog.csdn.net/article/details/145803512,作者:溟洵,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:C语言-------数据类型中signed、unsigned他们在不同数据类型中存储的不同体现并且与printf关系的总结。

      下一篇:【Linux 从基础到进阶】性能测试工具使用(sysbench、fio等)

      相关文章

      2025-05-06 09:20:29

      关于在代码中vector的一些使用

      关于在代码中vector的一些使用

      2025-05-06 09:20:29
      vector , 使用 , 初始化 , 数组 , 赋值
      2025-05-06 09:19:30

      【C/C++算法】从浅到深学习--- 简单模拟算法(图文兼备 + 源码详解)

      【C/C++算法】从浅到深学习--- 简单模拟算法(图文兼备 + 源码详解)

      2025-05-06 09:19:30
      模拟 , 算法 , 逻辑 , 题目 , 题解
      2025-05-06 09:19:30

      【30天玩转python】数据分析与可视化

      数据分析是通过数据提取、整理和分析来发现有用信息的过程,而数据可视化则通过图形和图表的方式,将数据转化为视觉化信息,以便快速理解数据趋势和模式。

      2025-05-06 09:19:30
      可视化 , 数据 , 数据分析 , 数组
      2025-05-06 09:19:30

      LeetCode刷题练习(最长公共前缀 C/C++两种解法)

      LeetCode刷题练习(最长公共前缀 C/C++两种解法)

      2025-05-06 09:19:30
      公共 , 前缀 , 字符串 , 最长
      2025-05-06 09:19:12

      IO流:字节输出流FileOutputStream的超详细用法

      IO流:字节输出流FileOutputStream的超详细用法

      2025-05-06 09:19:12
      int , 写入 , 字节 , 换行 , 数组
      2025-04-22 09:28:31

      零基础玩转C语言系列第五章——数组模块

      零基础玩转C语言系列第五章——数组模块

      2025-04-22 09:28:31
      下标 , 二维 , 数组 , 数组名 , 编译器
      2025-04-22 09:27:17

      指针的理解(三)

      指针的理解(三)

      2025-04-22 09:27:17
      int , 函数指针 , 变量 , 指针 , 数组
      2025-04-22 09:27:17

      蓝桥杯算法竞赛系列第九章·巧解哈希题,用这3种数据类型足矣

      蓝桥杯算法竞赛系列第九章·巧解哈希题,用这3种数据类型足矣

      2025-04-22 09:27:17
      key , map , nums , 哈希 , 数组
      2025-04-22 09:27:17

      随想录一刷·数组part2

      随想录一刷·数组part2

      2025-04-22 09:27:17
      数组 , 有序 , 链表
      2025-04-22 09:24:51

      蓝桥杯算法竞赛系列第十章·nSum问题的代码框架

      蓝桥杯算法竞赛系列第十章·nSum问题的代码框架

      2025-04-22 09:24:51
      nums , target , 数组
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      32886

      阅读量

      4912051

      查看更多

      最新文章

      关于在代码中vector的一些使用

      2025-05-06 09:20:29

      LeetCode刷题练习(最长公共前缀 C/C++两种解法)

      2025-05-06 09:19:30

      【C/C++算法】从浅到深学习--- 简单模拟算法(图文兼备 + 源码详解)

      2025-05-06 09:19:30

      零基础玩转C语言系列第五章——数组模块

      2025-04-22 09:28:31

      怎么只用语言实现扫雷?

      2025-04-22 09:24:51

      CUDA从入门到精通(四)——数据划分方法介绍

      2025-04-18 08:02:09

      查看更多

      热门文章

      Arrays类的使用

      2023-06-08 06:23:00

      Python打乱列表/数组原顺序,新列表/数组中元素随机分布

      2023-04-13 09:36:44

      Python数组列表过滤

      2023-04-17 09:39:09

      Java 程序设计 第2章 Java基本语法 笔记

      2023-02-24 09:13:25

      Python numpy读取文件数组,转化行列矩阵存入文件

      2023-04-18 14:14:43

      Go 语言入门很简单 -- 6. 数组 #私藏项目实操分享#

      2023-04-18 14:14:25

      查看更多

      热门标签

      java Java python 编程开发 开发语言 代码 算法 线程 html Python 数组 C++ javascript c++ 元素
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      Python numpy读取文件数组,转化行列矩阵存入文件

      C++单调向量算法:1671得到山形数组的最少删除次数

      Python|“双指针法”解删除数组重复项问题

      Solidity语言学习笔记————13、固定大小字节数组

      用go语言,每一种货币都给定面值val[i],和拥有的数量cnt[i], 想知道目前拥有的货币,在钱数为1、2、3...m时,能找零成功的钱数有多少?

      【C++动态规划】2088. 统计农场中肥沃金字塔的数目|2104

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 权益商城
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 权益商城
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号