前缀和差分

本文详细介绍了前缀和及其在一维和二维数组中的应用,包括如何计算和查询,以及如何进行二维前缀和的拓展。此外,还探讨了差分操作,用于在常数时间内对数组区间进行加减操作,并给出了还原方法。内容涵盖一维和二维差分的构建、操作及还原步骤,是理解动态数据更新的实用技巧。
摘要由CSDN通过智能技术生成

欢迎到我的博客查看更多未公开的文章🈲🥰

前缀和

前缀和可以在 O ( 1 ) O(1) O(1)时间内的计算一块区域的总和

一维前缀和

3127. 来,骗

一维前缀和

// 计算 
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];
}

一维前缀和拓展:斜着的一维前缀和

力扣 1878. 矩阵中最大的三个菱形和

原理和普通一维前缀和一样,但是需要找到对应方向上所有点坐标的递推公式:

斜一维前缀和

// 构建
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;
}

截屏2021-05-29 17.48.50
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[x11][y11]S2=prefix[1][3]S1=prefix[x11][y2]prefix[x11][y11]S3=prefix[3][1]S1=prefix[x2][y11]prefix[x11][y11]sum=prefix[3][3]S1S2S3=prefix[x2][y2]+prefix[x11][y11]prefix[x11][y2]prefix[x2][y11]

//查询
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.进行完操作后还原

一维差分

797.差分

3617. 子矩形计数

核心公式:

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[i1](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[i1](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]+carr[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];
  }
}

欢迎到我的博客查看更多未公开的文章🈲🥰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值