欢迎到我的博客查看更多未公开的文章🈲🥰
前缀和
前缀和可以在 O ( 1 ) O(1) O(1)时间内的计算一块区域的总和
一维前缀和
// 计算
int[] getPrefix(int[] arr){
int n = arr.length;
int[] prefix = new int[n+1]; // 添加一位初始和,简化代码
for(int i=1; i<=n; i++){
prefix[i] = prefix[i-1] + arr[i-1];
}
return prefix;
}
// 查询
int getSum(int[] prefix, int l, int r){
return prefix[r] - prefix[l-1];
}
一维前缀和拓展:斜着的一维前缀和
原理和普通一维前缀和一样,但是需要找到对应方向上所有点坐标的递推公式:
// 构建
int n = matrix.length, n = matrix[0].length;
int[][] prefix1 = new int[n+2][m+2]; // 左上---右下
int[][] prefix2 = new int[n+2][m+2]; // 右上---左下
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
prefix1[i][j] = prefix[i-1][j-1] + matrix[i-1][j-1];
prefix2[i][j] = prefix[i-1][j+1] + matrix[i-1][j-1];
}
}
// 查询 : (x1, y1) --- (x2, y2)
sum = prefix[x1][y1] - prefix[x2-1][y2-1];
二维前缀和
// 计算
// prefix[i][j]表示从(0,0)到(i,j)这一矩形和总和
int[][] getPrefix(int[][] matrix){
int n = matrix.length, m = matrix[0].length;
int[][] prefix = new int[n+1][m+1];
for(int i=1; i<=n; i++){
for(int j=1; i<=m; j++){
prefix[i][j] = prefix[i-1][j] + prefix[i][j-1] - prefix[i-1][j-1] + matrix[i-1][j-1];
}
}
return prefix;
}
S
1
=
p
r
e
f
i
x
[
1
]
[
1
]
=
p
r
e
f
i
x
[
x
1
−
1
]
[
y
1
−
1
]
S
2
=
p
r
e
f
i
x
[
1
]
[
3
]
−
S
1
=
p
r
e
f
i
x
[
x
1
−
1
]
[
y
2
]
−
p
r
e
f
i
x
[
x
1
−
1
]
[
y
1
−
1
]
S
3
=
p
r
e
f
i
x
[
3
]
[
1
]
−
S
1
=
p
r
e
f
i
x
[
x
2
]
[
y
1
−
1
]
−
p
r
e
f
i
x
[
x
1
−
1
]
[
y
1
−
1
]
s
u
m
=
p
r
e
f
i
x
[
3
]
[
3
]
−
S
1
−
S
2
−
S
3
=
p
r
e
f
i
x
[
x
2
]
[
y
2
]
+
p
r
e
f
i
x
[
x
1
−
1
]
[
y
1
−
1
]
−
p
r
e
f
i
x
[
x
1
−
1
]
[
y
2
]
−
p
r
e
f
i
x
[
x
2
]
[
y
1
−
1
]
S_{1} = prefix[1][1] = prefix[x_{1}-1][y_{1}-1] \\ S_{2} = prefix[1][3] - S_{1} = prefix[x_{1}-1][y_{2}] - prefix[x_{1}-1][y_{1}-1] \\ S_{3} = prefix[3][1] - S_{1} = prefix[x_{2}][y_{1}-1] - prefix[x_{1}-1][y_{1}-1] \\ sum = prefix[3][3] - S_{1} - S_{2} - S_{3} \\ =prefix[x_{2}][y_{2}] + prefix[x_{1} -1][y_{1}-1] - prefix[x_{1}-1][y2] - prefix[x_{2}][y_{1}-1]
S1=prefix[1][1]=prefix[x1−1][y1−1]S2=prefix[1][3]−S1=prefix[x1−1][y2]−prefix[x1−1][y1−1]S3=prefix[3][1]−S1=prefix[x2][y1−1]−prefix[x1−1][y1−1]sum=prefix[3][3]−S1−S2−S3=prefix[x2][y2]+prefix[x1−1][y1−1]−prefix[x1−1][y2]−prefix[x2][y1−1]
//查询
int getSum(int[][] prefix, int x1, int y1, int x2, int y2){
return prefix[x2][y2] + prefix[x1][y1] - prefix[x1-1][y2] - prefix[x2][y1-1];
}
差分
可以用来在 O ( 1 ) O(1) O(1)时间内计算给一块区域的所有位置都加上或者减去一个数。
主要可以分为两步:1.构建差分数组。2.进行完操作后还原
一维差分
核心公式:
1.计算
d i f f [ 0 ] = a r r [ 0 ] diff[0] = arr[0] diff[0]=arr[0]
d i f f [ i ] = a r r [ i ] − a r r [ i − 1 ] ( i > 0 ) diff[i] = arr[i] - arr[i-1] (i>0) diff[i]=arr[i]−arr[i−1](i>0)
2.还原
d i f f [ 0 ] = d i f f [ 0 ] diff[0] = diff[0] diff[0]=diff[0]
d i f f [ i ] = d i f f [ i ] − d i f f [ i − 1 ] ( i > 0 ) diff[i] = diff[i]-diff[i-1](i>0) diff[i]=diff[i]−diff[i−1](i>0)
例子🌰:
d i f f [ 0 ] = a r r [ 0 ] diff[0] = arr[0] diff[0]=arr[0]
d i f f [ 1 ] = a r r [ 1 ] − a r r [ 0 ] diff[1] = arr[1] - arr[0] diff[1]=arr[1]−arr[0]
d i f f [ 2 ] = a r r [ 2 ] − a r r [ 1 ] diff[2] = arr[2] - arr[1] diff[2]=arr[2]−arr[1]
d i f f [ 3 ] = a r r [ 3 ] − a r r [ 2 ] diff[3] = arr[3] - arr[2] diff[3]=arr[3]−arr[2]
给下标(1,2)内的所有点都加上常数c
d i f f [ 1 ] = d i f f [ 1 ] + c = a r r [ 1 ] − a r r [ 0 ] + c diff[1] = diff[1] + c = arr[1] - arr[0] + c diff[1]=diff[1]+c=arr[1]−arr[0]+c
d i f f [ 3 ] = d i f f [ 3 ] − c = a r r [ 3 ] − a r r [ 2 ] − c diff[3] = diff[3] - c = arr[3] - arr[2] - c diff[3]=diff[3]−c=arr[3]−arr[2]−c
还原:
d i f f [ 1 ] = d i f f [ 1 ] + d i f f [ 0 ] = a r r [ 1 ] − a r r [ 0 ] + c − a r r [ 0 ] = a r r [ 1 ] + c diff[1] = diff[1] + diff[0] = arr[1] - arr[0] + c - arr[0] = arr[1] + c diff[1]=diff[1]+diff[0]=arr[1]−arr[0]+c−arr[0]=arr[1]+c
d i f f [ 2 ] = d i f f [ 2 ] + d i f f [ 1 ] = a r r [ 2 ] − a r r [ 1 ] + a r r [ 1 ] + c = a r r [ 2 ] + c diff[2] = diff[2] + diff[1] = arr[2] - arr[1] + arr[1] + c = arr[2] + c diff[2]=diff[2]+diff[1]=arr[2]−arr[1]+arr[1]+c=arr[2]+c
d i f f [ 3 ] = d i f f [ 3 ] + d i f f [ 2 ] = a r r [ 3 ] − a r r [ 2 ] − c + a r r [ 2 ] + c = a r r [ 3 ] diff[3] = diff[3] + diff[2] = arr[3] - arr[2] - c + arr[2] + c = arr[3] diff[3]=diff[3]+diff[2]=arr[3]−arr[2]−c+arr[2]+c=arr[3]
// 1.构建差分数组
int n = arr.length;
int[] diff = new int[n+1]; // 多一位保存diff[n]
for(int i=0; i<n; i++){
diff[i] += arr[i];
diff[i+1] -= arr[i];
}
// 操作:如,为在下标(2, 5)之间的所有数都加上 c
diff[2] += c;
diff[5+1] -= c;
// 2.还原
for(int i=1; i<n; i++){
diff[i] += diff[i-1];
}
二维差分
1.构建
// 构建
int n = arr.length, m = arr[0].length;
int[][] diff = new int[n+2][m+2]; // 加两维是为了简化边界和防止越界
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
int t = arr[i-1][j-1];
diff[i][j] += t;
diff[i+1][j+1] += t;
diff[i][j+1] -= t;
diff[i+1][j] -= t;
}
}
2.操作:为点(x1, y1) , (x2, y2)确定的矩形中的所有点都加上常数c
// 操作
diff[x1][y1] += c;
diff[x2][y2] += c;
diff[x1][y2+1] -= c;
diff[x2+1][y1] -= c;
3.还原
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
diff[i][j] += diff[i-1][j] + diff[i][j-1] - diff[i-1][j-1];
}
}
欢迎到我的博客查看更多未公开的文章🈲🥰