二维数组前缀和有什么用?
求A[i][j]和A[m][n]之间所有元素加起来的总和。
定义:
sun[i][j]是A[0][0]到A[i][j]的前缀和
sum[x1,y1][x2,y2]=sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]
那sum[i][j]要怎么求呢?
sum[i][j]=A[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]
也就是该元素A[i][j]左侧第一个和上方第一个的sum值相加再减去重复加上的部分。
关于边界问题:
当i=0,j=0时 sum[0][0]=A[0][0]
sum[0,0]0,0=A[0][0]
当i等于0时就变成了一维前缀和
sum[0][j]=sum[0][j-1]+A[0][j]
sum[0,y1][0,y2]=sum[0][y2]-sum[0][y1-1]
当j等于0时此时只有第一列,同理为一维前缀和
sum[i][0]=sum[i-1][0]+A[i][0]
sum[x1,0][x2,0]=sum[x2][0]-sum[x1-1][0]
代码如下:
#include<iostream>
#include<Windows.h>
using namespace std;
const int n=3,m=4;
int A[n][m]={
{1,5,6,8},
{9,6,7,3},
{5,3,2,4},
};
int sum[n][m];
//构造sum表
int per_sum(){
sum[0][0]=A[0][0];
for(int j=1;j<m;j++)//第一行
sum[0][j]=sum[0][j-1]+A[0][j];
for(int i=1;i<n;i++)//第一列
sum[i][0]=sum[i-1][0]+A[i][0];
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+A[i][j];
}
}
}
int get_sum(int x1,int y1,int x2,int y2){
int res;
if(x1==0&&x2==0)
return res=sum[x2][y2];
if(x1==0)
return res=sum[x2][y2]-sum[x2][y1-1];
if(y1==0)
return res=sum[x2][y2]-sum[x1-1][y2];
return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}
int main(){
per_sum();
cout<<get_sum(1,1,2,2)<<endl;
cout<<get_sum(0,1,1,3)<<endl;
system("pause");
return 0;
}
per_sum()函数相当于是构造了一张sum表,这张表的里的内容是[0][0]到该点[x][y]之间所有元素的和。
这张表的构造方式是首先构造第一行和第一列,然后构造其他元素时用到第一行和第一列的值。
get_sum()为(x1,y1)到(x2,y2)之间元素值的和。这里要讨论边界问题,因为sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1]的前提是x1,y1 x2,y2大于0的情况,所以要讨论各自为零和都为零的情况。
最终结果如下:
总结一下: