算法精讲------前缀和:小白也能秒懂的时空魔法 ✨
📖 本文配套练习:力扣前缀和专题
🧑💻 建议边看边敲代码体验更佳哦~
🌰 从存钱罐说起------什么是前缀和?
想象你有个存钱罐📦,每天记录存入金额:
天数 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
金额 | 2 | 5 | 1 | 3 | 4 |
如果要算第3天到第5天存了多少钱,传统做法是:1+3+4=8元💰 前缀和的做法是:预先计算累计金额,这样就能快速查询任意区间的和!
java
// 前缀和数组计算(索引从1开始更直观)
int[] nums = {2,5,1,3,4};
int[] preSum = new int[nums.length+1];
for(int i=1; i<=nums.length; i++){
preSum[i] = preSum[i-1] + nums[i-1];
}
// 得到 [0,2,7,8,11,15]
🧩 一维前缀和实战教学
例题1:基础查询(力扣303)
graph LR
A[原始数组] --> B[构造前缀数组]
B --> C{查询请求}
C --> D[计算差值]
Java实现细节:
java
class NumArray {
private int[] preSum;
// 初始化:O(n)时间
public NumArray(int[] nums) {
preSum = new int[nums.length + 1];
for (int i = 1; i <= nums.length; i++) {
preSum[i] = preSum[i-1] + nums[i-1];
}
}
// 查询:O(1)时间
public int sumRange(int left, int right) {
return preSum[right+1] - preSum[left];
}
}
🔍 关键点解析:
preSum[0] = 0
作为哨兵值,统一计算逻辑- 数组索引从1开始,与天数自然对应
- 查询时注意right+1的边界处理
🚀 二维前缀和升级版
例题2:矩阵区域和(力扣304)
假设我们有如下矩阵:
1 2 3
4 5 6
7 8 9
对应的二维前缀和矩阵:
java
// 构造公式:
preSum[i][j] = preSum[i-1][j]
+ preSum[i][j-1]
- preSum[i-1][j-1]
+ matrix[i-1][j-1];
// 结果矩阵:
0 0 0 0
0 1 3 6
0 5 12 21
0 12 27 45
可视化推导:
graph TD
A[原点0,0] --> B[计算第一行]
B --> C[逐行填充]
C --> D[处理重叠区域]
Java实现:
java
class NumMatrix {
private int[][] preSum;
public NumMatrix(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
preSum = new int[m+1][n+1];
for(int i=1; i<=m; i++){
for(int j=1; j<=n; j++){
preSum[i][j] = preSum[i-1][j]
+ preSum[i][j-1]
- preSum[i-1][j-1]
+ matrix[i-1][j-1];
}
}
}
public int sumRegion(int row1, int col1, int row2, int col2) {
return preSum[row2+1][col2+1]
- preSum[row1][col2+1]
- preSum[row2+1][col1]
+ preSum[row1][col1];
}
}
💡 高阶技巧:前缀和+哈希表
例题3:统计子数组(力扣560)
java
class Solution {
public int subarraySum(int[] nums, int k) {
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0, 1); // 初始状态:前缀和为0出现1次
int count = 0, preSum = 0;
for(int num : nums){
preSum += num;
// 查找之前是否存在preSum - k
if(map.containsKey(preSum - k)){
count += map.get(preSum - k);
}
map.put(preSum, map.getOrDefault(preSum, 0) + 1);
}
return count;
}
}
🔑 核心思想: 通过哈希表记录前缀和出现次数,将时间复杂度从O(n²)降到O(n)
📝 总结表格:不同场景的时空复杂度
场景 | 暴力法时间复杂度 | 前缀和优化后 |
---|---|---|
一维区间查询 | O(n) per query | O(1) |
二维矩阵查询 | O(mn) | O(1) |
统计子数组 | O(n²) | O(n) |
🛠️ 前缀和四步使用法
- 识别问题:是否涉及区间累加和?
- 构建preSum:注意初始化方式和索引偏移
- 推导公式:找出preSum之间的数学关系
- 处理边界:特别是二维场景的四个角点计算
🎯 现在尝试用前缀和解这道题吧:724. 寻找数组的中心下标