【算法拾光】前缀和|一维前缀和 + 二维前缀和

题目 1:一维前缀和

链接:303. 区域和检索 - 数组不可变 - 力扣(LeetCode)

题目分析

实现一个类,输入数组 nums,多次查询区间 [left, right] 的区间和。数组不会修改。 示例: nums = [-2, 0, 3, -5, 2, -1] sumRange(0,2) → 1 sumRange(2,5) → -1 sumRange(0,5) → -3 核心:如果每次查询都遍历区间,单次查询 O (n),查询次数多就超时。前缀和预处理之后,单次查询 O (1)。

算法原理

定义前缀和数组 preSum,下标从 1 开始 (规避边界判断): preSum[0] = 0 preSum[i] = nums[0] + nums[1] + ... + nums[i-1]

区间 [l, r](原数组下标,从 0 开始)的和公式: sum = preSum[r + 1] - preSum[l]

预处理 O (n),每次查询 O (1)。

代码编写

cpp 复制代码
class NumArray {
public:
    vector<int> preSum;
    NumArray(vector<int>& nums) {
        int n = nums.size();
        preSum.resize(n + 1, 0);
        for(int i = 1; i <= n; i++) {
            preSum[i] = preSum[i - 1] + nums[i - 1];
        }
    }
    
    int sumRange(int left, int right) {
        return preSum[right + 1] - preSum[left];
    }
};

总结

一维前缀和核心:偏移 1 位,preSum 0=0 。记住公式:原数组 [l,r] 和 = preSum[r+1] - preSum[l]。适合静态数组区间求和,数组不能修改;如果单点修改,需要用树状数组 / 线段树。


题目 2:二维前缀和

链接:304. 二维区域和检索 - 矩阵不可变 - 力扣(LeetCode)

题目分析

给定二维矩阵,多次查询子矩形 (row1, col1) 到 (row2, col2) 的和,矩阵不变。 示例: matrix = \[3,0,1,4,2, 5,6,3,2,1, 1,2,0,1,5, 4,1,0,1,7, 1,0,3,0,5 ] sumRegion (2,1,4,3) → 8 核心:二维区间求和,暴力每次遍历矩形 O (mn),多次查询太慢。二维前缀和预处理,查询 O (1)。

算法原理

前缀和数组 preSum 下标从 1 开始 ,preSum[i][j] 代表左上角 (1,1) 到 (i,j) 的矩形和。 递推公式: preSum[i][j] = matrix[i-1][j-1] + preSum[i-1][j] + preSum[i][j-1] - preSum[i-1][j-1]

子矩形 (x1,y1) ~ (x2,y2)(原矩阵下标,从 0 开始): 映射到前缀和下标:a=x1+1, b=y1+1, c=x2+1, d=y2+1 查询公式: sum = preSum[c][d] - preSum[a-1][d] - preSum[c][b-1] + preSum[a-1][b-1]

原理:减去上方一块、左边一块,多减了左上角重叠部分,再加回来。

代码编写

cpp 复制代码
class NumMatrix {
public:
    vector<vector<int>> preSum;
    NumMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size();
        if(m == 0) return;
        int n = matrix[0].size();
        preSum.assign(m + 1, vector<int>(n + 1, 0));
        for(int i = 1; i <= m; i++) {
            for(int j = 1; j <= n; j++) {
                preSum[i][j] = matrix[i-1][j-1] + preSum[i-1][j] + preSum[i][j-1] - preSum[i-1][j-1];
            }
        }
    }
    
    int sumRegion(int row1, int col1, int row2, int col2) {
        int a = row1 + 1, b = col1 + 1;
        int c = row2 + 1, d = col2 + 1;
        return preSum[c][d] - preSum[a-1][d] - preSum[c][b-1] + preSum[a-1][b-1];
    }
};

总结

二维前缀和重点:容斥原理,先加、再减、再加回重叠部分。同样适合静态矩阵,预处理 O (mn),查询 O (1)。下标偏移 1 是为了不用单独判断 i=0 或 j=0 的边界。


本篇总结

本篇是前缀和两大基础模板,笔试高频:

  1. 一维前缀和:preSum 0=0,[l,r] 和 = preSum[r+1]-preSum[l]
  2. 二维前缀和:递推用容斥,查询也用容斥,下标全部 + 1 简化边界

前缀和适用场景:数组 / 矩阵不变,多次区间求和。 ⚠️ 注意:如果题目会单点修改,前缀和不再合适,要换树状数组。

相关推荐
释厄6232 小时前
矢量词汇向下不向上公理即词汇归位定律——肤浅即表面
java·人工智能·算法·去中心化·1024程序员节
海绵宝宝转agent2 小时前
Leetcode100+面经
java·笔记·学习·算法·leetcode·深度优先
Shaoshing2 小时前
LeetCode100 283.移动零
java·数据结构·算法·leetcode
海绵宝宝转agent2 小时前
LeetCode100个人题解+java面经总结
java·开发语言·笔记·学习·算法
飞Link11 小时前
什么是 AirSim?一文读懂无人机仿真平台
python·算法·无人机
一去不复返的通信er13 小时前
贪心算法-合并区间(LeetCode 56)
算法·leetcode·贪心算法
Shaoshing13 小时前
LeetCode100 49. 字母异位词分组
java·算法
YFJ_mily14 小时前
第二届区块链技术与基础模型国际学术会议(BTFM2027)
算法·区块链·能源·智能系统·rdlink研发家·机器人自动化