目录
1、引入
1.1、什么叫前缀和?
前缀和(prefix sum)是一种常用的数据处理技巧。在一个数列中,前缀和指的是从数列开始到当前位置的所有数的和。也就是说,前缀和是一个新的数列,其第i个元素是原始数列中前i个元素的和,前缀和有可以分为一维前缀和和二维前缀和,一维指的是一个序列,二维指的是一个矩阵的一部分子矩阵的数的和。
例如下图的一维前缀和:
二维前缀和:
2、前缀和算法
例题形式更好理解
2.1、一维前缀和
例如,给定一个序列,让我们求序列的前缀和序列,并且给出一个区间内的前缀和,一维前缀和比较简单。
设S[i]为序列a的前缀和数组,那么我们归纳可得出:
S[1]=a[1],当i=1;
S[i]=S[i-1]+a[i],当i>1,
如果寻找区间[l,r]区间的前缀和,只需要S[r]-S[l-1];
C++:
#include <iostream>
using namespace std;
const int N=1e5+10;
int a[N],s[N];
int main(){
int n,m,l,r;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);//读入字符
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];//计算前缀和
while(m--){
scanf("%d%d",&l,&r);
cout << s[r]-s[l-1]<<endl;
}
}
Java:
import java.util.Scanner;
public class PrefixSum {
public final static int N= 100010;
public final static int[] a=new int[N];
public final static int[] s=new int[N];
public static void main(String[] args) {
int n,m,l,r;
Scanner scanner=new Scanner(System.in);
n=scanner.nextInt();
m=scanner.nextInt();
for(int i=1;i<=n;i++)a[i]=scanner.nextInt();
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
while(m>0){
l=scanner.nextInt();
r=scanner.nextInt();
System.out.println(s[r]-s[l-1]);
m--;
}
}
}
2.2、二维前缀和
给定一个二维数组,让我们求二维数组某个区域的值的和,应该如何来求?
第一步:思考如果对二维数组值进行求和,然后算出前缀和数组,可这样思考:
第二步:那么求出前缀和之后,如果算一个二维区域的前缀和呢,我们可以把其看做一个连续平面思考:
通过上面两种思路,我们可以推出公式:
1.求出二维数组的前缀和:S[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1]
注意:这里使用+=,而不是=,是因为本身也要加上去。
2.求出一个区域的前缀和:S[x2][y2]-S[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
C++实现:
/*
第一行包含三个整数 n,m,q
接下来 n行,每行包含 m个整数,表示整数矩阵。
接下来 q行,每行包含四个整数 x1,y1,x2,y2,表示一组询问
*/
#include<iostream>
using namespace std;
const int N=1e4+10;
int s[N][N];
int main(){
int n,m,q;
cin >> n >> m >> q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin >> s[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
}
int x1,x2,y1,y2;
while(q--){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
cout << s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1] << endl;
}
}
Java实现
import java.util.Scanner;
public class PrefixSumTwo {
public final static int N= 1010;
public final static int[][] s=new int[N][N];
public static void main(String[] args) {
int n,m,q;
Scanner scanner = new Scanner(System.in);
n=scanner.nextInt();
m=scanner.nextInt();
q=scanner.nextInt();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[i][j]=scanner.nextInt();
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
}
int x1,y1,x2,y2;
while(q>0){
x1= scanner.nextInt();
y1= scanner.nextInt();
x2= scanner.nextInt();
y2= scanner.nextInt();
System.out.println(s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]);
q--;
}
}
}