一、 一维数组前缀
一维数组前缀和:构造一个与原数组长度相同的新数组 pre,pre[i] 表示原数组 arr 中 从第0个元素到第i个元素的所有元素累加和,核心价值是把「区间和查询」的时间复杂度从O(n)降到O(1)。
二、 核心公式(2个必记)
- 前缀和数组构建公式
◦ 边界:pre[0] = arr[0](第一个元素的前缀和就是自身)
◦ 递推:pre[i] = pre[i-1] + arr[i](i ≥ 1,当前前缀和 = 前一个前缀和 + 原数组当前元素)
- 区间和查询公式(求原数组 [l, r] 闭区间的和)
◦ sum(l,r) = pre[r] - (l == 0 ? 0 : pre[l-1])
◦ 简化技巧:若让前缀和数组从下标1开始,公式直接简化为 sum(l,r) = pre[r] - pre[l-1],无需判断边界,开发中更常用。
三、 2种常用实现(C语言代码)
实现1:下标从0开始(基础版,适配数组默认下标)
#include <stdio.h>int main() {
int arr[] = {2, 5, 1, 3, 4}; // 原数组
int n = sizeof(arr)/sizeof(arr[0]); // 原数组长度
int pre[n]; // 前缀和数组
// 1. 构建前缀和数组
pre[0] = arr[0];
for (int i = 1; i < n; i++) {
pre[i] = pre[i-1] + arr[i];
}
// 2. 查询区间和:比如查 [1,3](下标从0开始,对应元素5,1,3)
int l = 1, r = 3;
int sum = pre[r] - pre[l-1]; // l≠0,直接减pre[l-1]
printf("前缀和数组:");
for (int i = 0; i < n; i++) printf("%d ", pre[i]); // 输出:2 7 8 11 15
printf("\n区间[%d,%d]和:%d", l, r, sum); // 输出:9
return 0;
}
实现2:下标从1开始(实用版,无边界判断)
java
#include <stdio.h>
int main() {
int arr[] = {2, 5, 1, 3, 4};
int n = sizeof(arr)/sizeof(arr[0]);
int pre[n+1]; // 前缀和数组长度+1,下标从1开始
pre[0] = 0; // 前缀和第0位设为0,作为基准
// 1. 构建前缀和数组
for (int i = 1; i <= n; i++) {
pre[i] = pre[i-1] + arr[i-1]; // 原数组下标仍从0开始
}
// 2. 查询区间和:查原数组[1,3],直接用公式 pre[r]-pre[l-1]
int l = 2, r = 4; // 对应原数组下标1-3,前缀和下标同步+1
int sum = pre[r] - pre[l-1];
printf("前缀和数组:");
for (int i = 1; i <= n; i++) printf("%d ", pre[i]); // 输出:2 7 8 11 15
printf("\n区间和:%d", sum); // 输出:9
return 0;
}
四、 核心优势 & 适用场景
-
优势:一次构建,多次查询,构建仅需O(n),每次查询仅需O(1),适合频繁查区间和的场景。
-
适用场景:数组元素固定(不频繁修改)、频繁求任意区间和(如算法题、统计类需求)。
五、 易错点
-
下标混淆:务必区分原数组和前缀和数组的下标对应关系,推荐用下标从1开始的写法,减少错误。
-
数组越界:构建前缀和时,循环边界要对应数组长度,避免pre[i]超出数组范围。
-
元素修改:若原数组元素频繁修改,前缀和需要重新构建,此时不如直接遍历求和高效。
我可以帮你针对一道具体的区间和算法题,用前缀和写完整解题代码,需要吗?