C++算法 —— 前缀和

一、【模版】前缀和

1.链接

【模板】前缀和_牛客题霸_牛客网 (nowcoder.com)

2.描述

3.思路

前缀和的思想其实就是一种简单的动态规划,以i位置记录从头位置到i位置的和,然后间接的求一段连续区间的数组和,时间复杂度是O(n) + O(q),这种思想在实际中是为了应对多次查询的情况,当q特别大时,采用这种方式的时间复杂度就会较低

4.参考代码

#include <iostream>
#include <vector>
using namespace std;int main() 
{int n,q;cin >> n >> q;vector<int> arr(n+1,0);for(int i = 1;i <= n;i++) cin >> arr[i];vector<long long> dp(n+1,0);for(int i = 1;i <= n ; i++) dp[i] = dp[i-1] + arr[i];while(q--){int l,r;cin >> l >> r;cout << dp[r] - dp[l-1] << endl;}return 0;
}

二、二维前缀和

1.链接

【模板】二维前缀和_牛客题霸_牛客网 (nowcoder.com)

2.描述

3.思路

该题我们采用动态规划的定式思路去分析得到前缀和的表,并且分析如何使用

4.参考代码

核心的思路就是上面的动归分析已经如何使用前缀和表格的部分,剩下的就是在实际写代码时候的一些细节

1.测试用例中包含较大的数据,因此在dp表格中存放的值类型需要使用long long

2.一般按照思路是先载入数据,然后再动归建立dp表,但由于我们这里dp表和arr都选择使用多一行一列的辅助位置去进行的初始化,这两个步骤可以放在同一个for循环里一起执行,但先后顺序不能变,一定是先载入arr的数据,再去执行dp

#include <iostream>
using namespace std;
#include<vector>int main() 
{//加载数据int n,m,q;cin >> n >> m >> q;vector<vector<int>> arr(n+1,vector<int>(m+1,0));vector<vector<long long>> dp(n+1,vector<long long>(m+1,0));//利用动态规划思路建立前缀和的表格//写代码的时候发现,两个步骤可以合并,因此放在一起执行for(int i = 1;i<=n;i++){for(int j = 1;j<=m;j++){cin >> arr[i][j];//加载数据dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + arr[i][j];//动归创建前缀和表格}}int x1,x2,y1,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;
}

三、寻找数组的中心下标

1.链接

724. 寻找数组的中心下标 - 力扣(LeetCode)

2.描述

3.思路

先建立前缀和表格,然后遍历一遍下标位置,去比对当前下标的前后两个部分的和是否相同,若是相同则说明当前下标就是目标值,直接返回,若是遍历结束后都没有找到,说明不存在,返回-1

要注意前缀表中和题目给的数组两者之间的映射关系,最好画图去分析,又或者可以建立多一个后缀表,去对应遍历

4.参考代码

class Solution {
public:int pivotIndex(vector<int>& nums) {int n = nums.size();vector<int> dp(n+1,0);for(int i = 1;i<=n;i++) dp[i] = dp[i-1] + nums[i-1];for(int i = 0;i<n;i++){if(dp[i] == dp[n] - dp[i+1]) return i;}return -1;}
};

四、除自身以外数组的乘积

1.链接

238. 除自身以外数组的乘积 - 力扣(LeetCode)

2.描述

3.思路

题目要求的数组是除开自己的其余所有数的乘积,那么可以将ret[i]分成两部分

1.nums[0] * nums[1] * nums[2] * ... * nums[i-1] (i位置的左半部分乘积)

2.nums[i+1] * nums[i+2] * nums[i+3] * ... *  nums[n-1](i位置的右半部分乘积)

因此我们可以利用前缀和的思想,去将前半部分和后半部分分别进行制表

head[i]:表示以i位置结束,从第头到该位置的乘积

tail[i]:表示从i位置开始,到最末尾的乘积

然后遍历填表即可

4.参考代码

class Solution {
public:vector<int> productExceptSelf(vector<int>& nums) {int n = nums.size();vector<int> ret(n);vector<int> head(n+1,1);//添加辅助位要注意映射关系vector<int> tail(n+2,1);//注意,这里需要先初始化tail的第一个值for(int i = 1;i<=n;i++) head[i] = head[i-1]*nums[i-1];for(int i = n;i>=1;i--) tail[i] = tail[i+1]*nums[i-1];//得到两个表格后,遍历填表即可for(int i = 0;i<n;i++) ret[i] = head[i]*tail[i+2];return ret;}
};

五、和为k的子数组

1.链接

560. 和为 K 的子数组 - 力扣(LeetCode)

2.描述

3.思路

4.参考代码

class Solution {
public:int subarraySum(vector<int>& nums, int k) {int sum = 0;map<int,int> hash;int count = 0;for(int i = 0;i<nums.size();i++){hash[sum]++;sum += nums[i];//此时sum为i位置的前缀和count += hash[sum-k];}return count;}
};

5.代码分析

六、和可被K整除的子数组

1.链接

974. 和可被 K 整除的子数组 - 力扣(LeetCode)

2.描述

3.思路

4.参考代码

class Solution 
{
public:int subarraysDivByK(vector<int>& nums, int k) {map<int,int> hash;int sum = nums[0];int count = 0;for(int i = 0;i<nums.size();i++){hash[(sum%k+k)%k]++;sum+=nums[i];count += hash[(sum%k+k)%k];}return count;}
};

七、连续数组

1.链接

525. 连续数组 - 力扣(LeetCode)

2.描述

3.思路

改题目若是将所有的0都换成-1,则依然和上一题的思路是一样的,都是通过前缀和去转化

4.参考代码

class Solution 
{
public:int findMaxLength(vector<int>& nums) {unordered_map<int,int> hash;int ret = 0;int sum = 0;hash[0] = -1;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;}
};

八、矩阵区域和

1.链接

1314. 矩阵区域和 - 力扣(LeetCode)

2.描述

这题描述较复杂,大致意思就是,给你一个m*n的矩阵,并且给你一整数k,然后你得返回一个相同规模的矩阵,而这个矩阵内的数据要求是:

以【i,j】位置向上下左右各延伸k个单位然后围成的矩阵和,越界的部分视为0,例如:

3.思路

这题就是对二维前缀和的一个应用,对二维前缀和的表格建立和使用,需要熟练掌握分析,而不要去死记公式,得到二维前缀和表和得到使用方法后再根据这题进行分析,这里不重复分析,随便花个草图去分析即可

建表的递推公式:dp[i][j] = dp[i-1][j] + dp[i][j-1]  - dp[i-1][j-1] + mat[i][j]

使用表格的公式:dp[x2][y2] - dp[x1-1][y2] - dp[x2][y1-1] + dp[x1-1][y1-1]

分析:

这题首先是如何确定x1、y1、x2、y2的问题,画图分析可得(太简单了略)

(x1,y1)    = (i-k,y-k)      , (x2,y2)  = (i+k,y+k)  

除了找到对应的矩阵区间,我们很容易想到还需要对边界条件进行除了,i-k和j-k是有可能越界的,因此最多我们不能让它们小于(0,0)的位置,i+k和j+k同理,最大不能大于(m-1,n-1)的位置

x1 = max(0,i-k);   y1 = max(0,y-k);     x2 = min(m-1,i+k);     y2 = min(n-1,j+k);

还有一个细节就是下标的映射关系要注意,因为在初始化dp表(前缀和表)时,我们会添加一个辅助位,而题目给的数组是从0开始的,dp表则是从1开始,所以写代码时要注意映射关系即可

4.参考代码

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>> dp(m+1,vector<int>(n+1,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];//注意映射关系//开始用表填返回表vector<vector<int>> answer(m,vector<int>(n));for(int i = 0;i<m;i++){for(int j = 0;j<n;j++){int x1 = max(0,i-k), y1=max(0,j-k);int x2 = min(m-1,i+k), y2 = min(n-1,j+k);answer[i][j] = dp[x2+1][y2+1] - dp[x1][y2+1] - dp[x2+1][y1] + dp[x1][y1];//注意映射关系}}return answer;}
};

总结

本篇内容是关于前缀和的算法思想和应用,整理了一些经典的题目,从简单到难逐步递进,提供链接可以直接到力扣上做,也提供了描述可以直接通过看本篇文章去尝试思考解题,提供了参考思路和测试通过的代码(C++),整理学习下来后,个人认为一个是需要掌握一维和二维的表格建立和基本使用,还有相对较难的,但也有迹可循的一种用前缀和将题目转化,利用哈希表去优化效率的思想,参考五到七题,这个思路相对重要

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

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

相关文章

解密项目管理工具数据安全:防火防盗,保密有招

相关数据显示&#xff0c;2021年中国数字经济规模总量达到45.5万亿元&#xff0c;占到国内GDP总量的39.8%。数字经济已经渗入我们工作生活的方方面面&#xff0c;项目管理工具就是其中之一&#xff0c;在数据安全备受重视的今天如何保证项目管理工具的数据安全性&#xff1f;Zo…

java中LocalDateTime,Instant,ZoneID,ZoneDateTime,DateTimeFormatter类常用的API

LoaclDate LocalTime LocalDateTime类 LocalDate &#xff1a;代表本地日期&#xff08;年&#xff0c;月&#xff0c;日&#xff0c;星期&#xff09; LocalTime:代表本地时间&#xff08;时&#xff0c;分&#xff0c;秒&#xff0c;纳秒&#xff09;API LocalDateTime:代…

【leetcode面试经典150题】13.除自身以外数组的乘积(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

达梦disql登录数据库显示“未连接”

问题&#xff1a;达梦数据库在使用disql登录时&#xff0c;显示“未连接”。 指定了IP和端口号还是连接异常。 [dmdbatest ~]$ disql sysdba/Dameng123 disql V8 SQL> select * from v$instances; 未连接 SQL> exit [dmdbatest ~]$ disql sysdba/Dameng123localhost:52…

C++运算符重载如何模拟数学表达式,或模拟Python sympy和numpy

在人工智能数学基础一书中&#xff0c;下面是一题Python求函数极限的例子&#xff1a; 【例2.6】使用Python编程求 lim( x → 1) (x^2 - 1 / x - 1) ————————————————————————————————————————— import sympy from sympy import oo…

医疗大数据现状及发展问题探讨

医疗大数据&#xff0c;作为近年来备受瞩目的领域&#xff0c;其发展和变化的速度之快令人瞩目。从最初的概念炒作到如今的实际应用&#xff0c;短短三年多的时间&#xff0c;我们已经见证了医疗大数据领域的巨大变革。 临床数据的公开透明&#xff0c;为医疗大数据的利用提供…

Java基础知识总结(41)

&#xff08;1&#xff09; 在Java语言中&#xff0c;根据定义变量的位置不同&#xff0c;可以将变量分成两大类&#xff1b;成员变量和局部变量。 &#xff08;2&#xff09;成员变量 成员变量包括类变量&#xff08;用static修饰的变量&#xff09;和实例变量&#xff08;不用…

用Skimage学习数字图像处理(018):图像形态学处理(上)

本节开始讨论图像形态学处理&#xff0c;这是上篇&#xff0c;将介绍与二值形态学相关的内容&#xff0c;重点介绍两种基本的二值形态学操作&#xff1a;腐蚀和膨胀&#xff0c;以及三种复合二值形态学操作&#xff1a;开、闭和击中击不中变换。 目录 9.1 基础 9.2 基本操作…

ubuntu远程服务部署,Docker,蓝牙无线局域网,SSH,VNC,xfce4,NextTerminal,宝塔,NPS/NPC,gost,openwrt

开机启动 /lib/systemd/system/rc-local.service 添加 [Install] WantedBymulti-user.target Aliasrc-local.service/etc/rc.local #!/bin/sh 添加开机启动需要执行的脚本sudo chmod 777 /lib/systemd/system/rc-local.service sudo chmod x /etc/rc.local #systemctl dis…

漫谈GIS和空间数据库技术

1 GIS和CAD有啥区别 地理信息系统&#xff08;GIS&#xff09;和计算机辅助设计&#xff08;CAD&#xff09;是两种不同的技术&#xff0c;它们在功能、应用和数据处理方面有着显著的区别。以下是根据搜索结果得出的GIS和CAD的主要区别&#xff1a; 1. **数据处理的侧重点不同…

金陵科技学院软件工程学院软件工程专业

感兴趣的小伙伴可以私信我哦~~ 是笔者写的各种高质量作业和实验哦~~ 感兴趣的小伙伴可以私信我哦~~ 是笔者写的各种高质量作业和实验哦~~ 感兴趣的小伙伴可以私信我哦~~ 是笔者写的各种高质量作业和实验哦~~ 感兴趣的小伙伴可以私信我哦~~ 是笔者写的各种高质量作业和实验哦…

【其他】灾害预警,科技助力:手机地震预警功能设置指导

22024年4月3日7时58分在台湾花莲县海域遭遇了一场7.3级的强烈地震&#xff0c;震源深度12公里&#xff0c;震中位于北纬23.81度&#xff0c;东经121.74度&#xff0c;距台湾岛约14公里。震中5公里范围内平均海拔约-3560米。这场突如其来的自然灾害给当地居民的生活带来了巨大的…

从永远到永远-Git中tag的使用

Git中tag的使用 1.tag的作用2.使用背景3.tag的使用1.种类2.创建标签3.查看标签3.推送标签4. 删除标签: 4.idea可视化操作1.创建标签2.推送标签 999 删除、指定commit、验证暂时不表 1.tag的作用 Tag(标签)用来记录某个特定的提交(commit)。一个 Tag 被用来标记重要的历史节点&…

物联网实战--入门篇之(八)嵌入式-空气净化器

目录 一、风扇调速 二、通讯协议 三、净化器运行逻辑 一、风扇调速 单片机是不能直接驱动电机的&#xff0c;因为主芯片的驱动电流比较小(50mA左右)&#xff0c;他们之间正常还要有个电机驱动器&#xff0c;常用的有TB6612、L298和L9110等&#xff0c;目前项目用的这个电机它…

工具篇之Hutool

一、概述 1.1介绍 Hutool是一个小而全的Java工具类库&#xff0c;通过静态方法封装&#xff0c;降低相关API的学习成本&#xff0c;提高工作效率&#xff0c;使Java拥有函数式语言般的优雅&#xff0c;让Java语言也可以“甜甜的”。 Hutool中的工具方法来自于每个用户的精雕细…

猫头虎技术分享 || 断网了,还能ping127.0.0.1吗?

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

【数据分析面试】6.计算对话总数(SQL)

题目&#xff1a;计算对话总数 给定了名为 messenger_sends 的消息发送表格&#xff0c;找出总共有多少个唯一的对话。 注&#xff1a;在某些记录中&#xff0c;receiver_id 和 sender_id 从初始消息中互换了。这些记录应视为同一个对话。 示例&#xff1a; 输入&#xff1…

Linux进程控制 Part 1

Linux进程控制 文章目录 Linux进程控制Linux系统任务管理的方法PCB的原型 Linux查看获取进程id的方式现象解释 Linux 进程的状态首先学习查看进程状态的命令常见的几种状态僵尸进程的危害 孤儿进程&#xff1a; 进程优先级概念&#xff1a;PRI and NI查看进程优先级的命令 环境…

wordpress全站开发指南-面向开发者及深度用户(全中文实操)--php函数

php函数 wordpress会封装一部分函数&#xff0c;比如bloginfo该函数的作用是直接调用你设置的你的网站的名称 示例 This is our amazing custom theme <?php echo 22; function myfirstfunction(){ echo 33; echo "<p>Hello ,this is my first function</…

2024-04-02(js)

1.将函数A作为参数传递给函数B&#xff0c;称A为回调函数 2.插件&#xff1a;就是别人写好的一些代码&#xff0c;我们只需要复制对应的代码&#xff0c;就可以直接实现对应的效果 3.js是一种单线程语言&#xff0c;同一时间只能做一件事 4.js先执行完所有的同步任务&#x…