算法精讲——前缀和:小白也能秒懂的时空魔法

算法精讲------前缀和:小白也能秒懂的时空魔法 ✨

📖 本文配套练习:力扣前缀和专题

🧑💻 建议边看边敲代码体验更佳哦~


🌰 从存钱罐说起------什么是前缀和?

想象你有个存钱罐📦,每天记录存入金额:

天数 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];
    }
}

🔍 关键点解析

  1. preSum[0] = 0 作为哨兵值,统一计算逻辑
  2. 数组索引从1开始,与天数自然对应
  3. 查询时注意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)

和为 K 的子数组

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)

🛠️ 前缀和四步使用法

  1. 识别问题:是否涉及区间累加和?
  2. 构建preSum:注意初始化方式和索引偏移
  3. 推导公式:找出preSum之间的数学关系
  4. 处理边界:特别是二维场景的四个角点计算

🎯 现在尝试用前缀和解这道题吧:724. 寻找数组的中心下标

相关推荐
vv安的浅唱3 分钟前
Golang基础笔记七之指针,值类型和引用类型
后端·go
陪我一起学编程15 分钟前
MySQL创建普通用户并为其分配相关权限的操作步骤
开发语言·数据库·后端·mysql·oracle
Heo1 小时前
调用通义千问大模型实现流式对话
前端·javascript·后端
Java水解2 小时前
RabbitMQ用法的6种核心模式全面解析
后端·rabbitmq
用户4099322502122 小时前
FastAPI的查询白名单和安全沙箱机制如何确保你的API坚不可摧?
前端·后端·github
前端小巷子2 小时前
深入 npm 模块安装机制
前端·javascript·面试
橙序员小站2 小时前
JDK17 前后写法对比:差点没认出是 Java
java·后端
肖哥弹架构2 小时前
Spring JDBCTemplate 十大性能优化秘籍:从慢如蜗牛到快如闪电!
java·后端·程序员
wenb1n2 小时前
【Oracle】套接字异常(SocketException)背后隐藏的Oracle问题:ORA-03137深度排查与解决之道
后端