C++ 前缀和

news2025/4/16 7:51:38

目录

1、DP34 【模板】前缀和

2、DP35 【模板】二维前缀和​编辑

3、724. 寻找数组的中心下标

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

5、560. 和为 K 的子数组 

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

7、525. 连续数组

8、1314. 矩阵区域和


1、DP34 【模板】前缀和

 思路:注意题中数组下标从1开始!!!

  • 我们使用一个循环遍历数组arr中的每个元素,并计算前缀和。在每次迭代中,我们将当前元素arr[i]加到前一个前缀和a[i-1]上,得到新的前缀和a[i]。这样,我们就可以通过累加数组元素来计算前缀和。
  • 具体地,a[i] = a[i - 1] + arr[i]表示第i个元素的前缀和等于前一个前缀和加上当前元素的值。这样,我们就可以通过一次遍历计算出整个数组的前缀和。
#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 + 1; i++) {
        cin >> arr[i];
    }
    vector<long long> a(n + 1);
    for (int i = 1; i < n + 1; i++) {
        a[i] = a[i - 1] + arr[i];
    }
    int l = 0, r = 0;
    while (q--) {
        cin >> l >> r;
        cout << a[r] - a[l - 1] << endl;
    }
    return 0;
}

2、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;
    }
}

3、724. 寻找数组的中心下标

思路:

  • 前缀和数组:a[i]表示[0,i-1]区间所有元素的和:a[i]=a[i-1]+nums[i-1]
  • 后缀和数组:b[i]表示[i+1,n-1]区间所有元素的和:b[i]=b[i+1]+nums[i+1]
  • 处理边界:f(0)=0,g(n-1)=0
class Solution {
public:
    int pivotIndex(vector<int>& nums) {
        int n = nums.size();
        vector<int> lsum(n), rsum(n);
        for (int i = 1; i < n; i++) {
            lsum[i] = lsum[i - 1] + nums[i - 1];
        }
        for (int j = n - 2; j >= 0; j--) {
            rsum[j] = rsum[j + 1] + nums[j + 1];
        }
        for (int i = 0; i < n; i++) {
            if (lsum[i] == rsum[i])
                return i;
        }
        return -1;
    }
};

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

思路:

  • f:表示前缀积:f[i]表示:[0,i-1]区间内所有元素的乘积:f[i]=f[i-1]*nums[i-1]
  • g:表示后缀积:g[i]表示:[i+1,n-1]区间内所有元素的乘积:g[i]=g[i+1]*nums[i+1]
  • 处理边界:f(0)=1,g(n-1)=1
class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n = nums.size();
        vector<int> lsum(n), rsum(n);
        lsum[0] = rsum[n - 1] = 1;
        for (int i = 1; i < n; i++) {
            lsum[i] = lsum[i - 1] * nums[i - 1];
        }
        for (int i = n - 2; i >= 0; i--) {
            rsum[i] = rsum[i + 1] * nums[i + 1];
        }
        vector<int> ret(n);
        for (int i = 0; i < n; i++) {
            ret[i] = lsum[i] * rsum[i];
        }
        return ret;
    }
};

5、560. 和为 K 的子数组 

思路:前缀和+哈希表(记录前缀和出现次数)统计sum-k出现次数。

class Solution {
public:
    int subarraySum(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        hash[0] = 1;
        int sum = 0, ret = 0;
        for (auto a : nums) {
            sum += a;
            //如sum-k存在,则证明当前和为k或存在两段连续区间相减后和为k
            if (hash.count(sum - k))
                ret += hash[sum - k];
            hash[sum]++;
        }
        return ret;
    }
};

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

思路:前缀和+哈希表(记录前缀和出现次数),其中,需要使用(sum % k + k) % k,对sum可能为负数的情况进行修正。

class Solution {
public:
    int subarraysDivByK(vector<int>& nums, int k) {
        unordered_map<int, int> hash;
        hash[0] = 1;
        int sum = 0, ret = 0;
        for (auto a : nums) {
            sum += a;
            int r = (sum % k + k) % k;
            if (hash.count(r))
                ret += hash[r];
            hash[r]++;
        }
        return ret;
    }
};

7、525. 连续数组

思路:前缀和+哈希表(记录前缀和出现位置),将0当作-1,转化为计算和为0的区间长度。

  • 将所有的0修改成-1;
  • 在数组中,找出最长的子数组使子数组中所有元素的和为0
class Solution {
public:
    int findMaxLength(vector<int>& nums) {
        unordered_map<int, int> hash;
        hash[0] = -1;
        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;
    }
};

8、1314. 矩阵区域和

思路: 二维前缀和

class Solution {
public:
    vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {
        int m = mat.size(), n = mat[0].size();
        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] + mat[i - 1][j - 1] -
                           dp[i - 1][j - 1];
            }
        }
        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;
    }
};

int m = mat.size(), n = mat[0].size();: 这里获取矩阵的行数 m 和列数 n

vector<vector<int>> dp(m + 1, vector<int>(n + 1));: 创建一个大小为 (m+1) x (n+1) 的二维数组 dp,用于存储矩阵的前缀和。

使用一个嵌套循环,用于计算矩阵的前缀和。通过动态规划的思想,dp[i][j] 表示以 (i-1, j-1) 为右下角的子矩阵的元素和。通过递推公式 dp[i][j] = dp[i-1][j] + dp[i][j-1] + mat[i-1][j-1] - dp[i-1][j-1],可以计算出每个位置的前缀和。

vector<vector<int>> ret(m, vector<int>(n));: 创建一个大小为 m x n 的二维数组 ret,用于存储最终的结果。

第二个嵌套循环,用于计算每个位置 (i, j) 的区域和。通过利用前缀和数组 dp,根据题目给出的条件计算出满足条件的元素和。

  • x1 = max(0, i - k) + 1 和 y1 = max(0, j - k) + 1 确定了左上角的坐标。
  • x2 = min(m - 1, i + k) + 1 和 y2 = min(n - 1, j + k) + 1 确定了右下角的坐标。
  • ret[i][j] 计算了以 (i, j) 为中心,边长为 2k+1 的正方形区域内的元素和。

最后,函数返回结果矩阵 ret,其中每个元素 ret[i][j] 是满足条件的元素和。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1474798.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Project_Euler-11 题解

Project_Euler-11 题解 题目 题目中给出的数据如下&#xff1a; 08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65 52 70 95 23 04 …

ESP32语音转文字齐护百度在线语音识别

一、导入(10分钟&#xff09; 学习目的 二、新授(70分钟) 1.预展示结果(5分钟) 2.本节课所用的软硬件(5分钟) 4.图形化块介绍(10分钟) 5.单个模块的简单使用(10分钟) 6.在线语音转换工具逻辑分析(10分钟) 7.在线语音转换工具分步实现(30分钟) 三、巩固练习(5分钟) 四、课堂小结…

考研数据结构算法机试训练1

中南大学上机压轴题 测试数据&#xff1a; 3 500 0.6 100 0.8 200 0.7 100 输出 390首先要对输入的折扣进行排序&#xff0c;优先使用比率低的z进行支付。 然后用lowcost记录目前多少钱是打过折的。T-lowcost就是剩余没打折的。 每次循环用上一个人的折扣额度。若所有人折扣额…

VR转接器:破解虚拟与现实边界的革命性设备

VR转接器&#xff0c;这一革命性的设备&#xff0c;为虚拟现实体验带来了前所未有的自由度。它巧妙地连接了虚拟与现实&#xff0c;使得用户在享受VR眼镜带来的奇幻世界的同时&#xff0c;也能自由地在现实世界中活动。这一设计的诞生&#xff0c;不仅解决了VR眼镜续航的瓶颈问…

react-组件基础

1.目标 能够使用函数创建组件 能够使用class创建组件 能够给React元素绑定事件 能够使用state和setState() 能够处理事件中的this指向问题 能够使用受控组件方式处理表单 2.目录 React组件介绍 React组件的两种创建方式 React事件处理 有状态组件和无状态组件 组件中的state…

Flink CDC 提取记录变更时间作为事件时间和 Hudi 表的 precombine.field 以及1970-01-01 取值问题

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

数据结构:树/二叉树

一、树的概念 逻辑结构&#xff1a;层次结构&#xff0c;一对多 节点&#xff1a;树中的一个数据元素根节点&#xff1a;树中的第一个节点&#xff0c;没有父节点孩子节点&#xff1a;该节点的直接下级节点父(亲)节点&#xff1a;该结点的直接上级节点兄弟节点&#xff1a;有…

代码随想录算法训练营第44天|● 完全背包 ● 518. 零钱兑换 II ● 377. 组合总和 Ⅳ

文章目录 ● 完全背包卡码网&#xff1a;52. 携带研究材料-完全背包理论练习代码&#xff1a; ● 518. 零钱兑换 II思路&#xff1a;五部曲 代码&#xff1a;滚动数组代码二&#xff1a;二维数组 ● 377. 组合总和 Ⅳ思路&#xff1a;五部曲 代码&#xff1a; ● 完全背包 卡码…

第十二篇【传奇开心果系列】Python文本和语音相互转换库技术点案例示例:深度解读SpeechRecognition语音转文本

传奇开心果系列 系列博文目录Python的文本和语音相互转换库技术点案例示例系列 博文目录前言一、SpeechRecognition语音转文本一般的操作步骤和示例代码二、SpeechRecognition 语音转文本的优势和特点三、易用性深度解读和示例代码四、多引擎支持深度解读和示例代码五、灵活性示…

windows系统使用Vscode在WSL调试golang本地进程

背景&#xff1a; windows10企业版 vscodegolang1.20 wsl编译运行。 vscode 使用本地wsl进行进程attach操作&#xff0c;发现&#xff1a;Access is denied. 本地进程启动&#xff0c;vscode调试进程。windows-Linux控制台: Starting: C:\Users\book\go\bin\dlv.exe dap --l…

express+mysql+vue,从零搭建一个商城管理系统5--用户注册

提示&#xff1a;学习express&#xff0c;搭建管理系统 文章目录 前言一、新建user表二、安装bcryptjs、MD5、body-parser三、修改config/db.js四、新建config/bcrypt.js五、新建models文件夹和models/user.js五、index.js引入使用body-parser六、修改routes/user.js七、启动项…

vscode不能远程连接ubuntu18.04.6

目录 问题解决Portable Mode 安装vscode 补充说明学习资料 问题 vscode远程ssh连接ubuntu18.04.6时&#xff0c;出现如下提示框&#xff0c;单击Learn More后&#xff0c;定位到问题。Can I run VS Code Server on older Linux distributions? 原始是&#xff1a;需要glibc …

LeetCode 热题 100 | 图论(上)

目录 1 200. 岛屿数量 2 994. 腐烂的橘子 2.1 智障遍历法 2.2 仿层序遍历法 菜鸟做题&#xff0c;语言是 C 1 200. 岛屿数量 解题思路&#xff1a; 遍历二维数组&#xff0c;寻找 “1”&#xff08;若找到则岛屿数量 1&#xff09;寻找与当前 “1” 直接或间接连接在…

未来新质生产力Agent的起源与应用

Agent是什么&#xff1f; AI Agent的发展经历了从哲学思想启蒙到计算机科学助力、专家系统兴起、机器学习崛起、深度学习突破等多个阶段。如今&#xff0c;AI Agent已经成为人工智能领域的重要组成部分&#xff0c;为人类带来了巨大的便利和发展机遇。早在古希腊时期&#xff0…

《opencv实用探索·二十二》支持向量机SVM用法

1、概述 在了解支持向量机SVM用法之前先了解一些概念&#xff1a; &#xff08;1&#xff09;线性可分和线性不可分 如果在一个二维空间有一堆样本&#xff0c;如下图所示&#xff0c;如果能找到一条线把这两类样本分开至线的两侧&#xff0c;那么这个样本集就是线性可分&#…

关于年化收益率的思考

近期&#xff0c;对于投资的年化收益率有一些思考&#xff0c;想着将这些思考整理一下&#xff0c;顺便也就记录在这里。 1. 计算方式 年化收益率常见的计算有三种&#xff1a;算数平均&#xff0c;几何平均&#xff0c;IRR。 1.1 算术平均 算数平均用于度量产品的回报率&a…

【Java EE初阶二十六】简单的表白墙(二)

2. 后端服务器部分 2.1 服务器分析 2.2 代码编写 2.2.2 前端发起一个ajax请求 2.2.3 服务器读取上述请求,并计算出响应 服务器需要使用 jackson 读取到前端这里的数据,并且进行解析&#xff1a; 代码运行图&#xff1a; 2.2.4 回到前端代码&#xff0c;处理服务器返回的响应…

vue项目从后端下载文件显示进度条或者loading

//API接口 export const exportDownload (params?: Object, peCallback?: Function) > {return new Promise((resolve, reject) > {axios({method: get,url: ,headers: {access_token: ${getToken()},},responseType: blob,params,onDownloadProgress: (pe) > {peC…

Flutter(三):Stack、Positioned、屏幕相关尺寸、Navigator路由跳转

页面尺寸 通知栏高度&#xff1a;MediaQuery.of(context).padding.top顶部导航高度&#xff1a;kToolbarHeight底部导航高度&#xff1a;kBottomNavigationBarHeight屏幕宽&#xff1a;MediaQuery.of(context).size.width屏幕高&#xff1a;MediaQuery.of(context).size.height…

SpringMVC 学习(十)之异常处理

目录 1 异常处理介绍 2 通过 SimpleMappingExceptionResolver 实现 3 通过接口 HandlerExceptionResolver 实现 4 通过 ExceptionHandler 注解实现&#xff08;推荐&#xff09; 1 异常处理介绍 在 SpringMVC中&#xff0c;异常处理器&#xff08;Exceptio…