赞
踩
先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新大数据全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注大数据)
我们知道存储矩阵往往需要很大的空间。如果题目有空间的限制,例如100M = 100 * 1024 *1024 个字节(byte),那么对于矩阵每个元素是 4 个字节的 int型 来说,可以计算出最大的 maxn = 5120。不过,也可以像前面例题一样,不定义差分矩阵 b[][]
,直接将原矩阵a[][]
看成自己的差分矩阵,这样一来就能剩下一半的空间了。
同前面一样,我们先考虑能不能直接暴力求解。可以看出,每次矩阵修改的复杂度是 O ( n 2 ) O(n^2) O(n2),共 m 次,总复杂度为 O ( m + n 2 ) O(m+n^2) O(m+n2),肯定会 TLE。 **( 1 ) 二 维 差 分 的 定 义 \color{Purple}(1)二维差分的定义 (1)二维差分的定义**
在一维差分中,原数组a[ ]是从第1个b[1]开始的差分数组 b[ ]的前缀和:a[x]= b[1] + b[2] + ··· + b[x]。
在二维差分中,a[ ][ ]是差分数组b[ ][ ]的前缀和,即将原点坐标`(1,1)`和坐标`(i,j)`围成的矩阵中,所有的b[ ][ ]相加等于a[ i ][ j ]。我们可以把每个`b[][]`看成一个小格;在坐标`(1,1)`和`(i,j)`所围成的范围内,所有小格子加起来的总面积,等于 `a[i][j]`。如下图中,每个格子的面积是一个 b[ ][ ],例如阴影格子是b[ i ][ j ],它由4个坐标点组成: ( i , j ) \color{CadetBlue}(i, j) (i,j)、 ( i − 1 , j ) \color{CadetBlue}(i - 1, j) (i−1,j)、 ( i , j − 1 ) \color{CadetBlue}(i, j - 1) (i,j−1)、 ( i − 1 , j − 1 ) \color{CadetBlue}(i - 1, j - 1) (i−1,j−1)。坐标点`(i, j)`的值是 a[ i ][ j ],它等于坐标`(1,1)`和`(i,j)`所围成的所有格子的总面积 。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a5ec5e5af0e24da89c541fe6f77b2d0e.png#pic_center) 把 每 个 a [ ] [ ] 看 成 总 面 积 , 把 每 个 b [ ] [ ] 看 成 小 格 子 的 面 积 把每个a[][] 看成总面积,把每个b[][]看成小格子的面积 把每个a[][]看成总面积,把每个b[][]看成小格子的面积
由上图我们可以得到二维差分的定义:在二维情况下,差分就变成了相邻a[][]
的"面积差’’,计算公式是:
b
[
i
]
[
j
]
=
a
[
i
]
[
j
]
−
a
[
i
−
1
]
[
j
]
−
a
[
i
]
[
j
−
1
]
a
[
i
−
1
]
[
j
−
1
]
\color{Red}b[i][j] = a[i][j] - a[i - 1][j] - a[i][j - 1] + a[i - 1][j - 1]
b[i][j]=a[i][j]−a[i−1][j]−a[i][j−1]+a[i−1][j−1]
即利用上图红色大面积 a [ i ] [ j ] \color{Maroon}a[i][j] a[i][j]减去两个小面积 a [ i − 1 ] [ j ] \color{Turquoise}a[i- 1][j] a[i−1][j]、 a [ i ] [ j ] \color{Green}a[i][j] a[i][j],由于两个小面积公共的部分`a[i-1][j -1]`被减去了 2 次,故要加回来 1 次 a [ i − 1 ] [ j − 1 ] \color{Yellow}a[i - 1][j - 1] a[i−1][j−1]。 **( 2 ) 二 维 区 间 修 改 \color{Purple}(2) 二维区间修改 (2)二维区间修改**
对于一维区间修改的操作,我们只需要修改区间的两个端点的b[]
值。那么相应地,在二维情况下,一块区间是一个矩阵,由4个端点,只需要修改这 4个 b[][]
值即可。如下图所示,
当我们对坐标点 (x1, y1) ~ (x2, y2)
所围成的区间进行修改时,对应的4个端点的操作应为:
b[x1][y1] += c; // 二维区间的起点
b[x1][y2 + 1] -= c; // 把 x看成常数,y从 y1 到 y2
b[x2 + 1][y1] -= c;// 把 y看成常熟,x从 x1 到 x2
b[x2 + 1][y2 + 1] += c;// 由于前面两式把 c 减去了 2 次,故要加回 1 次
【例题1】Monitor
题意:Xiaoteng 有一个 n×m 的矩形庄稼地,为了抓到小偷,安装了 p 个监控,每个监控都有一个矩形的监视范围,左上角为 (x1,y1),右下角为 (x2,y2)。小偷们会来偷 q 次,每次小偷们的作案地点都是一个矩形区域,左上角为 (x1,y1),右下角为 (x2,y2)。问每次小偷们作案时,能否看到全部的小偷。
思路:将每个监控的矩形监视区域里的每个数都加上 1,都操作在差分数组上。求差分数组的前缀和得到原数组,如果原数组中的值大于 1,说明该点被多个监控覆盖,我们只需要记 1 个即可。对于小偷们每次作案的矩形区域,看监控区域是否全部覆盖(是否全是1),如果全部覆盖(作案矩形同监控矩形的值相等)则输出 YES,否则,输出NO。
AcCode
#include<bits/stdc++.h> using namespace std; typedef long long LL; int main() { int n, m; while(~scanf("%d%d", &n, &m)) { vector<vector<int>> a(n + 10, vector<int>( m + 10, 0)); int k; scanf("%d", &k); while(k -- ) { int x1, y1, x2, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2); a[x1][y1] += 1; a[x2 + 1][y1] -= 1; a[x1][y2 + 1] -= 1; a[x2 + 1][y2 + 1] += 1; } // 求差分数组的前缀和,得到原数组的值 for(int i = 1; i <= n; i ++ ) for(int j = 1; j <= m; j ++ ) a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1]; // 如果被该区域被监控覆盖多次,则只记一次 for(int i = 1; i <= n; i ++ ) for(int j = 1; j <= m; j ++ ) if(a[i][j] > 1) a[i][j] = 1; // 对于小偷们每次作案的矩形区域,看监控区域是否全部覆盖(是否全是1) int p; scanf("%d", &p); while(p -- ) { int x1, y1, x2, y2; scanf("%d%d%d%d", &x1, &y1, &x2, &y2); int s1 = (x2 - x1 + 1) \* (y2 - y1 + 1); int s2 = f[x2][y2] - f[x1 - 1][y2] - f[x2][y1 - 1] + f[x1 - 1][y1 - 1]; if(s1 == s2) puts("YES"); else puts("NO"); } } return 0; }
三维已是人类空间想象的一个大跨度,其差分难度较为复杂,不过没关系,下面我们将利用空间立体图来逐一理解。 **( 1 ) 三 维 差 分 的 定 义 \color{Purple}(1)三维差分的定义 (1)三维差分的定义**
元素值用三维数组 a[][][]
来定义,差分数组b[][][]
也是三维的。与之前低维度的差分类似,把三维差分想象成立体空间的操作。与之对应的小立方块有 8 个顶点,所以三维的区间需要修改 8 个b[][][]
的值。
在二维差分中,`a[][]` 是差分数组 `b[][]`的前缀和,即原点坐标 (1,1)和 坐标(i,j)围成的矩阵面积。
在三维差分中,a[][][]
是差分数组 b[][][]
的前缀和,即原点坐标 (1, 1, 1) 和 坐标(i, j, k)围成的立体体积。同样地,我们把每个b[][][]
看成一个小立方体,在坐标(1, 1, 1)
~ (i , j,k)
所围成的空间中,所有小立体加起来的总体积即为a[i][j][k]
。如下图所示,每个小立方体由 8 个端点定义。坐标点(i,j,k)的值是 a[i][j][k]
; 图中小立方体的体积是差分数组 b[i][j][k]
的值。
类似的,在三维情况下,差分就变成了相邻的`a[][][]`的 ”体积差“。那么如何来写出差分的递推计算公式呢? 观察前面一、二维的前缀和我们可以发现,其前缀和规律十分吻合容斥原理。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a79059b5c1d045958ee2876f347bdd24.png#pic_center) 即对于 维 度 为 t \color{Red}维度为 t 维度为t 的前缀和,记 **S(t)** 为其前缀和的递推式,则我们有: S ( t ) = a [ t ] + ∑ n = 1 ∞ ( − 1 ) ( n − 1 ) S ( [ t − 1 ] 的 组 合 形 式 ) , n 为 − 1 的 个 数 S(t) = a[t]+ \sum\_{n = 1}^{∞}(-1)^{(n -1)}S( [t- 1]的组合形式),\color{CadetBlue}n~为 -1的个数 S(t)=a[t]+n=1∑∞(−1)(n−1)S([t−1]的组合形式),n 为−1的个数 所以对于三维的差分数组`b[][][]`,其递推式如下: b [ i ] [ j ] [ k ] = s [ i ] [ j ] [ k ] − s [ i − 1 ] [ j ] [ k ] − s [ i ] [ j − 1 ] [ k ] − s [ i ] [ j ] [ k − 1 ] + s [ i − 1 ] [ j − 1 ] [ k ] + s [ i − 1 ] [ j ] [ k − 1 ] + s [ i ] [ j − 1 ] [ k − 1 ] − s [ i − 1 ] [ j − 1 ] [ k − 1 ] \color{Red}b[i][j][k] = s[i][j][k]-s[i - 1][j][k] - s[i][j - 1][k] - s[i][j][k - 1] + s[i - 1][j - 1][k] + s[i - 1][j][k - 1] + s[i][j - 1][k - 1] - s[i - 1][j - 1][k - 1] b[i][j][k]=s[i][j][k]−s[i−1][j][k]−s[i][j−1][k]−s[i][j][k−1]+s[i−1][j−1][k]+s[i−1][j][k−1]+s[i][j−1][k−1]−s[i−1][j−1][k−1] 我们发现当维度为 t 的时候容斥的时间复杂度是 2 t 2^t 2t,而前缀和的总时间复杂度为 **O ( n t 2 t ) O(n ^t2^t) O(nt2t)**,即随着维度的升高,时间复杂度增大的很快,不过是可以优化到 **O ( n t t ) O(n^tt) O(ntt)** 的,但在此不展开讨论,因为在算法竞赛中很少遇到3维以上的前缀和,而对于 `t≤3`时 O ( n t 2 t ) O(n ^t2^t) O(nt2t) 与 O ( n t t ) O(n^tt) O(ntt)差别并不大,有兴趣的可自行查阅资料。 **( 2 ) 三 维 区 间 修 改 \color{Purple}(2) 三维区间修改 (2)三维区间修改**
在三维情况下,我们修改的是一个立方体,有8个顶点,故我们只需要修改这8个顶点的 差分数组b[][][]
的值即可。给出坐标点
(
x
1
,
y
1
)
(x1 , ~y1)
(x1, y1) ~
(
x
2
,
y
2
)
(x2 ,~y2)
(x2, y2)定义的区间,如下图所示
三
维
差
分
空
间
图
示
三维差分空间图示
三维差分空间图示
那么对应的 8个 b[][][]
的修改如下:
// 前面 b[x1][y1][z1] += c; // 坐标起点 b[x2 + 1][y1][z1] -= c; // 右下顶点的右边一个点 b[x1][y1][z2 + 1] -= c; // 左上顶点的上面一个点 b[x2 + 1][y1][z2 + 1] += c; // 右上顶点的斜右上方一个点 **网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。** **需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)** ![img](https://img-blog.csdnimg.cn/img_convert/34080a46a37056e66ec908256891b961.png) **一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!** 2t,而前缀和的总时间复杂度为 **O ( n t 2 t ) O(n ^t2^t) O(nt2t)**,即随着维度的升高,时间复杂度增大的很快,不过是可以优化到 **O ( n t t ) O(n^tt) O(ntt)** 的,但在此不展开讨论,因为在算法竞赛中很少遇到3维以上的前缀和,而对于 `t≤3`时 O ( n t 2 t ) O(n ^t2^t) O(nt2t) 与 O ( n t t ) O(n^tt) O(ntt)差别并不大,有兴趣的可自行查阅资料。 **( 2 ) 三 维 区 间 修 改 \color{Purple}(2) 三维区间修改 (2)三维区间修改** ~~~~ 在三维情况下,我们修改的是一个立方体,有8个顶点,故我们只需要修改这8个顶点的 差分数组`b[][][]`的值即可。给出坐标点 ( x 1 , y 1 ) (x1 , ~y1) (x1, y1) ~ ( x 2 , y 2 ) (x2 ,~y2) (x2, y2)定义的区间,如下图所示 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a8f0aa301ae54d86b008c4ff4f0055cc.png#pic_center) 三 维 差 分 空 间 图 示 三维差分空间图示 三维差分空间图示 那么对应的 8个 `b[][][]`的修改如下:
// 前面
b[x1][y1][z1] += c; // 坐标起点
b[x2 + 1][y1][z1] -= c; // 右下顶点的右边一个点
b[x1][y1][z2 + 1] -= c; // 左上顶点的上面一个点
b[x2 + 1][y1][z2 + 1] += c; // 右上顶点的斜右上方一个点
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)
[外链图片转存中…(img-MxnhYhP9-1713363630025)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。