前缀和与差分

前缀和

S [ i ] = Σ i j = 1 A [ j ] = S [ i − 1 ] + A [ i ] \text{S}\left[ \text{i} \right] =\underset{\text{j}=1}{\overset{\text{i}}{\Sigma}}\text{A}\left[ \text{j} \right] =\text{S}\left[ \text{i}-1 \right] +\text{A}\left[ \text{i} \right] S[i]=j=1ΣiA[j]=S[i1]+A[i]

说白了: S[i]就是前i项相加

  • 子段和

sum(l,r):从数组中第l数计算到第r个数的和。----- 也就是部分和,从l项累加到r项
sum ( l,r ) = S [ r ] − S [ l − 1 ] \text{sum}\left( \text{l,r} \right) =\text{S}\left[ \text{r} \right] -\text{S}\left[ \text{l}-1 \right] sum(l,r)=S[r]S[l1]

为了不用分类讨论,一般设置前缀和数组第一个元素为0,这样:nums[0]=pre[0+1]-pre[0]可得到

前缀和的类实现

class preSum{
public:preSum(const vector<int>& nums){pre.push_back(0);int n = nums.size();        for (int i = 1;i<=n;i++){//注意:如果没添加过pre[i],是不可以直接下标访问的pre.push_back(nums[i-1] + pre[i - 1]);}}int sumRange(int i,int j){//求:nums中[i,j]区间的和//0 nums[0] nums[0]+nums[1] nums[0]+nums[1]+nums[2] ....//如果是1开始,[i,j]和:pre[j]-pre[i-1],现在添加了0return pre[j+1] - pre[i];}int numsVal(int i){return sumRange(i, i);//return pre[i + 1] - pre[i];}void traverse(){for(auto val:pre){cout << val << " ";}cout << endl;}
private:vector<int> pre;
};

注意:[i,j]之间的和:包含j且j最大的和-不包含i且i-1最大的和

力扣53:求出连续和最大值

class Solution {
public:int maxSubArray(vector<int>& nums) {//建立nums的前缀和数组preint n=nums.size();vector<int> pre(n+1);for(int i=1;i<=n;i++)pre[i]=pre[i-1]+nums[i-1];//对于i从1——n,考虑每一个j:求max(pre[i]-pre[j-1])//优化:只要求出pre[j-1]最小值即可int ret=-100000000;int premin=pre[0];for(int i=1;i<=n;i++){ret=max(ret,pre[i]-premin);premin=min(premin,pre[i]);}return ret;}
};

//法二:直接记录前i-1个数的和的最小值

int maxSubArray(vector<int>& nums) {//建立nums的前缀和数组preint n=nums.size();vector<int> pre(n+1);for(int i=1;i<=n;i++)pre[i]=pre[i-1]+nums[i-1];//求前缀最小值:前i个数和的最小值是fix[i]vector<int> fix(n+1,0);fix[0]=pre[0];//这里其实就是遍历pre[i],记录最小的for(int i=1;i<=n;i++)fix[i]=min(pre[i],fix[i-1]);int ret=INT_MIN;int premin=pre[0];for(int i=1;i<=n;i++){//[j,i],求:pre[i]-pre[j-1]最小值//优化pre[i]-pre[j]最小,j<i//fix[i-1]就是[0,i-1]范围内前缀和最小即pre[j]ret=max(ret,pre[i]-fix[i-1]);}return ret;}

vector中resize()

resize(尺寸大小,多余的补充数值)

  • 该函数是少删多补,如果尺寸小于原数组大小就删去原数组的值
  • 如果尺寸大小多于原数组就补充第二个元素,默认为0
vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9};
nums.resize(7,9);
//1 2 3 4 5 6 7
nums.resize(3);//123
nums.resize(12);
//1 2 3 4 5 6 7 8 9 0 0 0
nums.resize(12,10);
//1 2 3 4 5 6 7 8 9 10 10 10

resize()改写,就可以pre[i]访问

 preSum(const vector<int>& nums){int n = nums.size();pre.resize(n + 1);for (int i = 1;i<=n;i++){pre[i]=nums[i-1] + pre[i - 1];}}

vector初始化

同resize(): vector vec(n,m)----n个m值,默认为0

 vector<int> aa(10, 22);vector<int> bb(7);
/*
22 22 22 22 22 22 22 22 22 22
0 0 0 0 0 0 0
*/

赋值,括号或者=

    vector<int> aa = {1, 2, 3, 4, 5};vector<int> bb(aa);vector<int> cc = aa;
//12345

迭代器或指针

    vector<int> aa = {1, 2, 3, 4, 5};vector<int> bb(aa.begin() + 1, aa.end() - 1);traverse(bb);//2,3,4  [,)

insert()

在给定位置前面插入元素,函数返回值是指向新加入元素的最前位置

    vector<int> aa = {1, 2, 3};auto it = aa.insert(aa.begin(), 100);//100,1,2,3cout << *it << " ";//100  vector<int> aa = {1, 2, 3};auto it = aa.insert(aa.end(), 100);//1,2,3,100cout << *it << " ";//100vector<int> aa = {1, 2, 3};auto it = aa.insert(aa.end()-2,3,77);//1,(77,77,77),2,3cout << *it << " ";//77vector<int> aa = {1, 2, 3};vector<int> bb = {7, 8, 9};auto it = aa.insert(aa.end() - 1, bb.begin(), bb.end()); // 1,2,(7,8,9),3cout << *it << " ";    // 7vector<int> aa = {1, 2, 3};int bb[3] = {7, 8, 9};auto it = aa.insert(aa.begin()+1, begin(bb), end(bb)); // 1,(7,8,9),2,3cout << *it << " ";    // 7

测试:

    vector<int> myvector(3, 100);vector<int>::iterator it;it = myvector.begin();it = myvector.insert(it, 200);
traverse(myvector);//(200),100,100,100myvector.insert(it, 2, 300);
traverse(myvector);//(300,300),200,100,100,100it = myvector.begin();std::vector<int> anothervector(2, 400);myvector.insert(it + 2, anothervector.begin(), anothervector.end());
traverse(myvector);//300,300,(400,400),200,100,100,100int myarray[] = {501, 502, 503};myvector.insert(myvector.begin(), myarray, myarray + 3);
traverse(myvector);//(501,502,503),300,300,400,400,200,100,100,100

原地前缀和:

   vector<int> vec = {1, 2, 3, 4, 5, 6};// 原地改成前缀和vec.insert(vec.begin(), 0);for (int i = 1; i <= vec.size(); i++) {vec[i] += vec[i - 1];}

二维前缀和

在这里插入图片描述

sum[i][j]:第i行和第j列构成的所有元素的和
相当于:sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]
即:去掉一行的和+去掉一列的和-去掉一行和一列的和(重叠部分)
然后加入当前下标元素值:a[i][j]

计算任意子矩阵和

在这里插入图片描述

以(p,q)为左上角,(i,j)为右下角

设S[i,j]是(0,0)位置到(i,j)位置的和,a[i,j]是(i,j)位置上的值

sum(p,q,i,j)=sum[i] [j] - sum[i] [q-1]-sum[p-1] [j]+sum[p-1] [q-1]

这种方式可以用O(n平方)初始化前缀和矩阵,然后靠O(1)计算出结果

差分

差分是一种与前缀和相对的策略,是求和的逆运算
给定数组a i , 其差分数组为: \text{给定数组a}_{\text{i}},\text{其差分数组为:} 给定数组ai,其差分数组为:

数组a = { a 1 , a 2 , a 3 , . . . , a n } \text{数组a}=\left\{ \text{a}_1,\text{a}_2,\text{a}_3,...,\text{a}_{\text{n}} \right\} 数组a={a1,a2,a3,...,an}

b i = { a 1 , i = 1 a i − a i − 1 2 ≤ i ≤ n \text{b}_{\text{i}}=\left\{ \begin{array}{l} \text{a}_1,\ \ \text{i}=1\\ \text{a}_{\text{i}}-\text{a}_{\text{i}-1}\ \ 2\le \text{i}\le \text{n}\\ \end{array} \right. bi={a1,  i=1aiai1  2in

在这里插入图片描述

给定一个数组nums,其差分数组diff就是第一个元素不变,其余:diff[i]=nums[i]-nums[i-1] ( i>=1)

class diffSum{ // 差分
public://计算差分数组diffSum(const vector<int>& vec){diff.resize(vec.size());diff[0] = vec[0];for (int i = 1; i < diff.size();i++){diff[i] = vec[i] - vec[i - 1];}}//对差分数组求前缀和就是原数组vector<int> getOrigin(){vector<int> res;res.resize(diff.size());res[0] = diff[0];for (int i = 1; i < diff.size();i++){res[i] = res[i-1]+diff[i];//注意是已储存的res[i-1]}return res;};
private:vector<int> diff;
};

数组a = { a 1 , a 2 , a 3 , . . . , a n } , 差分数组b = { a 1 , a 2 − a 1 , a 3 − a 2 , . . . , a n − a n − 1 } \text{数组a}=\left\{ \text{a}_1,\text{a}_2,\text{a}_3,...,\text{a}_{\text{n}} \right\} ,\text{差分数组b}=\left\{ \text{a}_1,\text{a}_2-\text{a}_1,\text{a}_3-\text{a}_2,...,\text{a}_{\text{n}}-\text{a}_{\text{n}-1} \right\} 数组a={a1,a2,a3,...,an},差分数组b={a1,a2a1,a3a2,...,anan1}

发现:a i = Σ i j = 1 b j , 也就是说:差分数组的前缀和就是差分数组的原数组 \text{发现:a}_{\text{i}}=\underset{\text{j}=1}{\overset{\text{i}}{\Sigma}}\text{b}_{\text{j}},\text{也就是说:差分数组的前缀和就是差分数组的原数组} 发现:ai=j=1Σibj,也就是说:差分数组的前缀和就是差分数组的原数组

也就是说如果知道了该数组的差分数组后,对差分数组求前缀和,就可以得到原数组

在这里插入图片描述

差分应用

假如对数组a的 [ l,r ] 区间的每一个数加上一个数k: \text{假如对数组a的}\left[ \text{l,r} \right] \text{区间的每一个数加上一个数k:} 假如对数组a[l,r]区间的每一个数加上一个数k:

{ a l + k,a l + 1 + k,a l + 2 + k,...,a r + k } ————这样连续区间的操作 \left\{ \text{a}_{\text{l}}+\text{k,a}_{\text{l}+1}+\text{k,a}_{\text{l}+2}+\text{k,...,a}_{\text{r}}+\text{k} \right\} \text{————这样连续区间的操作} {al+k,al+1+k,al+2+k,...,ar+k}————这样连续区间的操作

数组a = { a 1 , a 2 , a 3 , . . . , a n } , 差分数组: { a l + k,a l + 1 , a l + 2 , . . . , a r , a r + 1 − k } \text{数组a}=\left\{ \text{a}_1,\text{a}_2,\text{a}_3,...,\text{a}_{\text{n}} \right\} ,\text{差分数组:}\left\{ \text{a}_{\text{l}}+\text{k,a}_{\text{l}+1},\text{a}_{\text{l}+2},...,\text{a}_{\text{r}},\text{a}_{\text{r}+1}-\text{k} \right\} 数组a={a1,a2,a3,...,an},差分数组:{al+k,al+1,al+2,...,ar,ar+1k}

发现对原数组需要进行[l,r]的操作,但是在差分数组只需要对l和r+1位置做出改变,这样在效率上会提高

class diffSum{ // 差分
public://原数组进行了区间操作,差分数组两端改变void op(int l,int r,int val){diff[l] += val;if(r+1<diff.size()){diff[r + 1] -= val;}}
private:vector<int> diff;
};
//主程序测试vector<int> vec = {1, 5, 3, 7, 2, 8, 4};diffSum mm(vec);//mm是vec差分数组int l = 2, r = 5,val=7;for (int i = l; i <= r;i++)vec[i] += 7;mm.op(l, r, val);vector aa = mm.getOrigin();//做前缀和for(auto v:aa)cout << v << " ";cout << endl;

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

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

相关文章

后端程序员入门react笔记(一)

相关参考 react 首先&#xff0c;我们先大概了解一下什么是react以及react可以干什么。 React 是 Facebook 开源的一个用于构建用户界面的一款 JavaScript 库&#xff0c;主要用于构建 UI。 react的特点 声明式编程 react使用jsx进行渲染&#xff0c;这是一种类似html的语法…

打开双重el-dialog后出现遮罩后如何解决?

背景&#xff1a; 打开el-dialog后&#xff0c;再次打开另外一个el-dialog&#xff0c;出现以下画面。 解决方式&#xff1a;在第二个el-dialog增加append-to-body <el-dialog :close-on-click-modal“true” :visible.sync“createVisible” v-if“createVisible” :width…

BLIP-2:低计算视觉-语言预训练大模型

BLIP-2 BLIP 对比 BLIP-2BLIPBLIP-2如何在视觉和语言模型之间实现有效的信息交互&#xff0c;同时降低预训练的计算成本&#xff1f;视觉语言表示学习视觉到语言的生成学习模型架构设计 总结主要问题: 如何在计算效率和资源有限的情况下&#xff0c;有效地结合冻结的图像编码器…

Ray on ACK 实践探索之旅 - RayCluster 篇

作者&#xff1a;张杰、霍智鑫、行疾 什么是 Ray&#xff1f; Ray 是一个开源框架&#xff0c;专为构建可扩展的分布式应用程序而设计&#xff0c;旨在通过提供简单直观的 API&#xff0c;简化分布式计算的复杂性&#xff0c;让开发者能够便捷高效地编写并行和分布式 Python …

【MySQL】- 09 Select Count

【MySQL】- 09 Select Count 1认识COUNT2 COUNT(列名)、COUNT(常量)和COUNT(*)之间的区别3 COUNT(*)的优化 4 COUNT(*)和COUNT(1)5 COUNT(字段)总结 数据库查询相信很多人都不陌生&#xff0c;所有经常有人调侃程序员就是CRUD专员&#xff0c;这所谓的CRUD指的就是数据库的增删…

文心一言 VS 讯飞星火 VS chatgpt (194)-- 算法导论14.3 2题

二、用go语言&#xff0c;改写 INTERVAL-SEARCH 的代码&#xff0c;使得当所有区间都是开区间时&#xff0c;它也能正确地工作。 文心一言&#xff0c;代码正常运行&#xff1a; 在Go语言中&#xff0c;处理开区间&#xff08;open intervals&#xff09;时&#xff0c;我们需…

Qt环境搭建+简单程序实现

Qt是什么 Qt是一个跨平台的C图形用户界面应用程序框架。 框架的本质就是一群大佬发明的让菜鸡写出来的代码也也比较规范 也就是限制程序员的自由&#xff0c;让程序员写出来的代码规范。 库和框架有相似性。 库是被程序员调用的&#xff0c;&#xff08;程序员是主体&…

06 - python操作xml

认识XML 与HTML很像&#xff0c;是一种将数据存储在标记之间的标记语言&#xff0c;用户可以自定义自己的标记。 XML文件可以表示称为&#xff1a;XML树。这个XML树从根元素开始&#xff0c;根元素进一步分支到子元素。XML文件的每个元素都是XML树的一个节点&#xff0c;没有…

Flink实战五_直播礼物统计

接上文&#xff1a;Flink实战四_TableAPI&SQL 1、需求背景 现在网络直播平台非常火爆&#xff0c;在斗鱼这样的网络直播间&#xff0c;经常可以看到这样的总榜排名&#xff0c;体现了主播的人气值。 人气值计算规则&#xff1a;用户发送1条弹幕互动&#xff0c;赠送1个荧…

在线JSON转SQL工具

在线JSON转SQL - BTool在线工具软件&#xff0c;为开发者提供方便。在线JSON转SQL工具可以将JSON文件中的数据或者JSON对象转换为SQL插入语句&#xff0c;方便用户将数据导入到数据库中。用户可以通过简单的界面上传JSON文件&#xff0c;或者文本框输入&#xff0c;点击JSON转S…

Redis——SpringBoot整合Redis实战

1、基本配置 1.1、引入依赖 首先&#xff0c;建立Maven项目&#xff0c;在Maven项目中引入pom.xml文件&#xff1a; <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> &l…

计算机网络_1.6.3 计算机网络体系结构分层思想举例

1.6.3 计算机网络体系结构分层思想举例 1、实例引入&#xff08;用户在主机中使用浏览器访问web服务器&#xff09;2、从五层原理体系结构的角度研究该实例3、练习题 笔记来源&#xff1a; B站 《深入浅出计算机网络》课程 本节通过一个常见的网络应用实例&#xff0c;来介绍计…

灵活应对:策略模式在软件设计中的应用

策略模式是一种行为型设计模式&#xff0c;它允许定义一系列算法&#xff0c;并将每个算法封装起来&#xff0c;使它们可以互换使用。策略模式让算法的变化独立于使用算法的客户端&#xff0c;使得在不修改原有代码的情况下切换或扩展新的算法成为可能。 使用策略模式的场景包…

android inset 管理

目录 简介 Insets管理架构 Insets相关类图 app侧的类 WMS侧的类 inset show的流程 接口 流程 WMS侧确定InsetsSourceControl的流程 两个问题 窗口显示时不改变现有的inset状态 全屏窗口上的dialog 不显示statusbar问题 View 和 DecorView 设置insets信息 输入法显…

幻兽帕鲁客户端存档文件 - 云上备份和恢复教程

本文将详细介绍如何将幻兽帕鲁游戏客户端的存档文件备份至云端&#xff0c;以及如何从云端恢复存档数据至本地。 一、游戏存档备份场景 幻兽帕鲁的游戏进度存储在电脑本地磁盘上&#xff0c;游戏中创建的每个世界都对应一个本地存档文件夹。在玩游戏过程中&#xff0c;客户端…

智能边缘计算网关实现高效数据处理与实时响应-天拓四方

在当今时代&#xff0c;数据已经成为驱动业务决策的关键因素。然而&#xff0c;传统的数据处理方式往往存在延迟&#xff0c;无法满足实时性要求。此时&#xff0c;智能边缘计算网关应运而生&#xff0c;它能够将数据处理和分析的能力从中心服务器转移至设备边缘&#xff0c;大…

基于单片机控制的智能门锁设计

摘要&#xff1a;阐述基于STC15F2K60S2单片机控制的智能门锁设计&#xff0c;包括CPU控制单元模块、液晶显示LCD、 Wi-Fi模块&#xff0c;实现远程控制开门&#xff0c;密码开门的智能化功能。 关键词&#xff1a;控制技术&#xff0c;单片机&#xff0c;智能门锁&#xff0c;…

游戏视频录制软件推荐,打造专业电竞视频(3款)

随着游戏产业的快速发展&#xff0c;越来越多的玩家开始关注游戏视频录制软件。一款好的录制软件不仅可以帮助玩家记录游戏中的精彩瞬间&#xff0c;还可以让其与他人分享自己的游戏体验。接下来&#xff0c;我们将介绍三款热门的游戏视频录制软件&#xff0c;并对其进行详细的…

收放卷转动线速度计算FC(SCL+梯形图代码)

这篇博客是收放控制算法的基础系列,通过这篇文章的学习。大家能更好的理解收放卷控制里的前馈量计算,收放卷前馈PID大家可以参考下面链接文章: https://rxxw-control.blog.csdn.net/article/details/129352629https://rxxw-control.blog.csdn.net/article/details/12935262…

3D Line Mapping Revisited论文阅读

1. 代码地址 GitHub - cvg/limap: A toolbox for mapping and localization with line features. 2. 项目主页 3D Line Mapping Revisited 3. 摘要 提出了一种基于线的重建算法&#xff0c;Limap&#xff0c;可以从多视图图像中构建3D线地图&#xff0c;通过线三角化、精心…