前缀和知识点

前缀和 (Prefix Sum)

前缀和是一种预处理技术,通过预先计算数组的前缀和,将区间求和查询从 $O(n)$ 优化到 $O(1)$。

定义: prefix[i] 表示数组前 i 个元素的和(从下标 1 开始)。

$$ \text{prefix}[i] = \sum_{k=0}^{i-1} \text{nums}[k] $$

区间和公式: $\text{sum}(l, r) = \text{prefix}[r+1] - \text{prefix}[l]$


1
2
3
4
5
6
7
8
// 构建前缀和数组(长度 n+1,prefix[0] = 0)
vector<int> prefix(n + 1, 0);
for (int i = 0; i < n; i++) {
    prefix[i + 1] = prefix[i] + nums[i];
}

// 查询 [l, r] 的区间和(闭区间)
int rangeSum = prefix[r + 1] - prefix[l];
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 构建二维前缀和
vector<vector<int>> prefix(m + 1, vector<int>(n + 1, 0));
for (int i = 1; i <= m; i++) {
    for (int j = 1; j <= n; j++) {
        prefix[i][j] = prefix[i-1][j] + prefix[i][j-1]
                     - prefix[i-1][j-1] + matrix[i-1][j-1];
    }
}

// 查询 (r1,c1) 到 (r2,c2) 的子矩阵和
int sum = prefix[r2+1][c2+1] - prefix[r1][c2+1]
        - prefix[r2+1][c1] + prefix[r1][c1];

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 核心:prefix[j] - prefix[i] = k  →  prefix[i] = prefix[j] - k
int subarraySum(vector<int>& nums, int k) {
    unordered_map<int, int> cnt;
    cnt[0] = 1;  // 空前缀
    int pre = 0, ans = 0;
    for (int x : nums) {
        pre += x;
        if (cnt.count(pre - k)) ans += cnt[pre - k];
        cnt[pre]++;
    }
    return ans;
}
  • 求 和为 k 的最长子数组长度 → 哈希表存前缀和首次出现的下标
  • 求 和 ≥ k 的最短子数组 → 单调队列 + 前缀和
1
2
3
4
// 区间增减:对 [l, r] 所有元素 +val
diff[l] += val;
diff[r + 1] -= val;
// 最后做前缀和还原
  • 前缀异或:preXor[i+1] = preXor[i] ^ nums[i]
  • 区间异或和:preXor[r+1] ^ preXor[l]

题目关键点笔记
560. 和为 K 的子数组前缀和 + 哈希表计数题解
304. 二维区域和检索二维前缀和模板—
525. 连续数组0 变 -1,前缀和 + 哈希表题解
974. 和可被 K 整除的子数组同余定理:(pre % k + k) % k—
238. 除自身以外数组的乘积前缀积 + 后缀积—
437. 路径总和 III树上前缀和 + 回溯—
862. 和至少为 K 的最短子数组前缀和 + 单调队列—
1124. 表现良好的最长时间段前缀和 + 贪心—
1314. 矩阵区域和二维前缀和模板—

  1. 前缀和数组长度通常是 n+1,prefix[0] = 0,方便处理从头开始的区间
  2. 哈希表初始化 cnt[0] = 1(或 pos[0] = -1),表示空前缀
  3. 元素可能为负数时,前缀和不单调,不能用滑动窗口,要用哈希表
  4. 取模问题注意负数处理:(x % k + k) % k
  5. 二维前缀和注意容斥原理:加两次左上角

相关内容