前缀和算法详解:一维与二维前缀和模板实现
一维前缀和通过预处理数组将区间查询时间复杂度降为 O(1),递推公式为 dp[i] = dp[i-1] + arr[i]。二维前缀和在矩阵左上角添加零行零列以简化边界处理,递推公式为 sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + matrix[i-1][j-1]。查询区域和时利用容斥原理计算。文章提供了 C++ 和 Java 两种语言的完整实现代码,适用于解决静态区间求和问题。

一维前缀和通过预处理数组将区间查询时间复杂度降为 O(1),递推公式为 dp[i] = dp[i-1] + arr[i]。二维前缀和在矩阵左上角添加零行零列以简化边界处理,递推公式为 sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + matrix[i-1][j-1]。查询区域和时利用容斥原理计算。文章提供了 C++ 和 Java 两种语言的完整实现代码,适用于解决静态区间求和问题。


微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 1、读入数据
int n, m;
cin >> n >> m;
vector<int> arr(n + 1);
for(int i = 1; i <= n; i++) cin >> arr[i];
// 2、预处理出来一个前缀和数组
vector<long long> dp(n + 1);
for(int i = 1; i <= n; i++) dp[i] = dp[i - 1] + arr[i];
// 3、使用前缀和数组
int l = 0, r = 0;
while(m--) {
cin >> l >> r;
cout << dp[r] - dp[l - 1] << endl;
}
return 0;
}
时间复杂度:O(1),空间复杂度:O(1)。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int q = scan.nextInt();
// 为了防止溢出,用 long 类型的数组
int[] arr = new int[n + 1];
long[] dp = new long[n + 1];
for (int i = 1; i <= n; i++) {
arr[i] = scan.nextInt();
}
for (int i = 1; i <= n; i++) {
dp[i] = dp[i - 1] + arr[i];
}
while (q > 0) {
int l = scan.nextInt();
int r = scan.nextInt();
System.out.println(dp[r] - dp[l - 1]);
q--;
}
}
}
时间复杂度:O(1),空间复杂度:O(1)。
类比于一维数组的形式,如果我们能处理出来从 [0, 1] 位置到 [i, j] 位置这片区域内所有元素的累加和,就可以在 O(1) 的时间内,搞定矩阵内任意区域内所有元素的累加和。
在矩阵的最上面和最左边添加上一行和一列 0,这样可以省去非常多的边界条件的处理。处理后的矩阵下标直接从开始,能大胆使用 i-1,j-1 位置的值。
注意 dp 表与原数组 matrix 内的元素的映射关系:
sum[i][j] 的含义
递推方程
sum[i][j] = sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] + matrix[i-1][j-1]题目接口参数是原始矩阵下标,需先映射成 dp 表对应的下标(row1++, col1++, row2++, col2++)。
对于左上角 (row1, col1)、右下角 (row2, col2) 围成的区域(红色部分),利用容斥原理计算:
计算公式:
sum[row2][col2] - sum[row2][col1 - 1] - sum[row1 - 1][col2] + sum[row1 - 1][col1 - 1]
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 1. 读入数据
int n = 0, m = 0, q = 0;
cin >> n >> m >> q;
vector<vector<int>> arr(n + 1, vector<int>(m + 1));
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; j++)
cin >> arr[i][j];
// 2. 预处理前缀和矩阵
vector<vector<long long>> dp(n + 1, vector<long long>(m + 1));
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + arr[i][j] - dp[i - 1][j - 1];
// 3. 使用前缀和矩阵
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
while(q--) {
cin >> x1 >> y1 >> x2 >> y2;
cout << dp[x2][y2] - dp[x1 - ][y2] - dp[x2][y1 - ] + dp[x1 - ][y1 - ] << endl;
}
;
}
时间复杂度:O(1),空间复杂度:O(1)。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int q = in.nextInt();
int[][] arr = new int[n + 1][m + 1];
long[][] dp = new long[n + 1][m + 1];
// 读入数据
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
arr[i][j] = in.nextInt();
// 处理前缀和矩阵
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
dp[i][j] = dp[i - ][j] + dp[i][j - ] - dp[i - ][j - ] + arr[i][j];
(q > ) {
in.nextInt(), y1 = in.nextInt(), x2 = in.nextInt(), y2 = in.nextInt();
System.out.println(dp[x2][y2] - dp[x1 - ][y2] - dp[x2][y1 - ] + dp[x1 - ][y1 - ]);
q--;
}
}
}
时间复杂度:O(1),空间复杂度:O(1)。