(坚持每天写算法)算法复习与学习part1基础算法part1-11——差分
差分和前缀和是有联系的。
首先给定一个原数组a:a[1], a[2], a[3],,,,,, a[n];
然后我们构造一个数组b : b[1] ,b[2] , b[3],,,,,, b[i];
使得 a[i] = b[1] + b[2 ]+ b[3] +,,,,,, + b[i]
也就是说,a数组是b数组的前缀和数组,反过来我们把b数组叫做a数组的差分数组。换句话说,每一个a[i]都是b数组中从头开始的一段区间和。
这种b数组是需要自己构造的,而构造b数组的方法最简单直接的是:
a[0 ]= 0;
b[1] = a[1] - a[0];
b[2] = a[2] - a[1];
b[3] =a [3] - a[2];
........
b[n] = a[n] - a[n-1];
差分可以应用的问题:
给定区间[l ,r ],让我们把a数组中的[ l, r]区间中的每一个数都加上c,即 a[l] + c , a[l+1] + c , a[l+2] + c ,,,,,, a[r] + c;
使用差分,我们可以这么做:
首先让差分b数组中的 b[l] + c ,a数组变成 a[l] + c ,a[l+1] + c,,,,,, a[n] + c;
然后我们打个补丁,b[r+1] - c, a数组变成 a[r+1] - c,a[r+2] - c,,,,,,,a[n] - c;
这样子就可以得到上述问题的求解。
这个是题解:
这里是代码:
//差分 时间复杂度 o(m) #include<iostream> using namespace std; const int N = 1e5 + 10; int a[N], b[N]; int main() { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); b[i] = a[i] - a[i - 1]; //构建差分数组 } int l, r, c; while (m--) { scanf("%d%d%d", &l, &r, &c); b[l] += c; //将序列中[l, r]之间的每个数都加上c b[r + 1] -= c; } for (int i = 1; i <= n; i++) { a[i] = b[i] + a[i - 1]; //前缀和运算 printf("%d ", a[i]); } return 0; }
补充:前缀和和差分的题目,可以在写的时候直接浮现图解就可以确定下标。
其实差分不止是这一种,因为前缀和都有两种,一维和二维。
二维的差分数组,也是同一个道理,a[i][j] = b[1][1] + ……+b[i][j],a数组是b数组的前缀和数组。
在二维中,某一段区间用下面的图来表示的话就是以(x1,y1)为左端点,(x2,y2)为右端点的矩形。
二维利用差分想让某一段区间的a都加上某一个值,有点难说,建议画一个表示b数组的图还有一个表示a数组的图,还有一个表示这里是图解:
b[x1][ y1 ] +=c ; 对应图1 ,让整个a数组中蓝色矩形面积的元素都加上了c。
b[x1,][y2+1]-=c ; 对应图2 ,让整个a数组中绿色矩形面积的元素再减去c,使其内元素不发生改变。
b[x2+1][y1]- =c ; 对应图3 ,让整个a数组中紫色矩形面积的元素再减去c,使其内元素不发生改变。
b[x2+1][y2+1]+=c; 对应图4,,让整个a数组中红色矩形面积的元素再加上c,红色内的相当于被减了两次,再加上一次c,才能使其恢复。
(注意,x是行,y是列,不要看成函数了,要不然解不出来)
(还有的就是,是b[x2+1][y1]而不是b[x2][y1],因为如果选择了后者边界这些a数组是不会加c,而事实上a[x2][y2]也是边界上的。)
这个是代码;
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1010; int n, m , q; int a[N][N] , b[N][N]; void insert(int x1 , int y1 , int x2 , int y2 , int c){ b[x1][y1] += c; b[x1][y2 + 1] -= c; b[x2 + 1][y1] -= c; b[x2 + 1][y2 + 1] += c; } int main(){ cin>>n>>m>>q; for(int i = 1 ; i <= n ; i ++){ for(int j = 1 ; j <= m; j ++){ cin>>a[i][j]; } } for(int i = 1 ; i <= n ; i ++){ for(int j = 1 ; j <= m ; j ++){ insert(i,j,i,j,a[i][j]); } } while(q --){ int x1,y1,x2,y2,c; cin >>x1 >>y1>>x2>>y2>>c; insert(x1,y1,x2,y2,c); } for(int i = 1 ; i <= n ; i ++){ for(int j = 1 ; j <= m ; j ++){ b[i][j] += b[i-1][j] + b[i][j-1] - b[i-1][j-1];//其实这里是求a,b的前缀和是a } } for(int i = 1 ; i <= n ; i ++){ for(int j = 1 ; j <= m ; j++){ printf("%d " , b[i][j]); } puts(" ");//发现要空行系统才能识别 } }
参考链接:AcWing 797. 差分 【c++详细题解】 - AcWing(写的是真的好)
时间复杂度:O(n)和O(n^2)
本文作者:程序计算机人
本文链接:https://www.cnblogs.com/clina/p/17977662
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步