算法每日双题精讲 —— 前缀和(【模板】一维前缀和,【模板】二维前缀和)

news2025/2/3 15:13:45

在算法竞赛与日常编程中,前缀和是一种极为实用的预处理技巧,能显著提升处理区间和问题的效率。今天,我们就来深入剖析一维前缀和与二维前缀和这两个经典模板。

一、【模板】一维前缀和

题目描述

给定一个长度为 n n n 的整数数组 a a a,我们需要完成以下两个任务:

  1. 预处理数组,得到前缀和数组。
  2. 能够快速查询数组中任意区间 [ l , r ] [l, r] [l,r] 0 ≤ l ≤ r < n 0 \leq l \leq r < n 0lr<n)内所有元素的和。

算法原理

一维前缀和的核心思想是预先计算数组中每个位置之前所有元素的总和。设前缀和数组为 s s s,其中 s [ i ] s[i] s[i] 表示数组 a a a 中前 i i i 个元素的和( i i i 1 1 1 开始),那么有递推公式:
[s[i] = s[i - 1]+a[i - 1]]
这里 s [ 0 ] = 0 s[0]=0 s[0]=0,是为了方便处理边界情况。

当我们需要查询区间 [ l , r ] [l, r] [l,r] 的和时,根据前缀和的性质,该区间的和可以通过 s [ r + 1 ] − s [ l ] s[r + 1]-s[l] s[r+1]s[l] 快速得到。这是因为 s [ r + 1 ] s[r + 1] s[r+1] 包含了前 r + 1 r + 1 r+1 个元素的和, s [ l ] s[l] s[l] 包含了前 l l l 个元素的和,两者相减就得到了区间 [ l , r ] [l, r] [l,r] 的和。

在这里插入图片描述

在这里插入图片描述

C++ 代码实现

#include <iostream>
#include <vector>

using namespace std;

// 计算一维前缀和数组
vector<int> calculatePrefixSum(const vector<int>& a) {
    int n = a.size();
    vector<int> s(n + 1, 0);
    for (int i = 1; i <= n; ++i) {
        s[i] = s[i - 1] + a[i - 1];
    }
    return s;
}

// 查询区间 [l, r] 的和
int querySum(const vector<int>& s, int l, int r) {
    return s[r + 1] - s[l];
}

int main() {
    vector<int> a = {1, 2, 3, 4, 5};
    vector<int> s = calculatePrefixSum(a);

    int l = 1, r = 3;
    cout << "The sum of the interval [" << l << ", " << r << "] is: " << querySum(s, l, r) << endl;

    return 0;
}

复杂度分析

  • 时间复杂度:计算前缀和数组的时间复杂度为 O ( n ) O(n) O(n),因为需要遍历数组一次。每次查询区间和的时间复杂度为 O ( 1 ) O(1) O(1),这使得在多次查询的场景下,一维前缀和算法具有很高的效率。
  • 空间复杂度:需要额外的长度为 n + 1 n + 1 n+1 的数组来存储前缀和,因此空间复杂度为 O ( n ) O(n) O(n)

二、【模板】二维前缀和

题目描述

给定一个 m × n m \times n m×n 的二维整数矩阵 A A A,我们要完成以下任务:

  1. 预处理矩阵,得到二维前缀和矩阵。
  2. 能够快速查询矩阵中任意子矩阵 [ ( x 1 , y 1 ) , ( x 2 , y 2 ) ] [(x_1, y_1), (x_2, y_2)] [(x1,y1),(x2,y2)] 0 ≤ x 1 ≤ x 2 < m 0 \leq x_1 \leq x_2 < m 0x1x2<m 0 ≤ y 1 ≤ y 2 < n 0 \leq y_1 \leq y_2 < n 0y1y2<n)内所有元素的和。

算法原理

对于二维前缀和,我们定义 S [ i ] [ j ] S[i][j] S[i][j] 表示矩阵 A A A 中从左上角 ( 0 , 0 ) (0, 0) (0,0) 到右下角 ( i − 1 , j − 1 ) (i - 1, j - 1) (i1,j1) 这个子矩阵内所有元素的和( i i i j j j 1 1 1 开始)。其递推公式如下:
S [ i ] [ j ] = S [ i − 1 ] [ j ] + S [ i ] [ j − 1 ] − S [ i − 1 ] [ j − 1 ] + A [ i − 1 ] [ j − 1 ] S[i][j]=S[i - 1][j]+S[i][j - 1]-S[i - 1][j - 1]+A[i - 1][j - 1] S[i][j]=S[i1][j]+S[i][j1]S[i1][j1]+A[i1][j1]
这里减去 S [ i − 1 ] [ j − 1 ] S[i - 1][j - 1] S[i1][j1] 是为了避免重复计算。

当查询子矩阵 [ ( x 1 , y 1 ) , ( x 2 , y 2 ) ] [(x_1, y_1), (x_2, y_2)] [(x1,y1),(x2,y2)] 的和时,公式为:
s u m = S [ x 2 + 1 ] [ y 2 + 1 ] − S [ x 1 ] [ y 2 + 1 ] − S [ x 2 + 1 ] [ y 1 ] + S [ x 1 ] [ y 1 ] sum = S[x_2 + 1][y_2 + 1]-S[x_1][y_2 + 1]-S[x_2 + 1][y_1]+S[x_1][y_1] sum=S[x2+1][y2+1]S[x1][y2+1]S[x2+1][y1]+S[x1][y1]

在这里插入图片描述

在这里插入图片描述

C++ 代码实现

#include <iostream>
#include <vector>

using namespace std;

// 计算二维前缀和矩阵
vector<vector<int>> calculateTwoDPrefixSum(const vector<vector<int>>& A) {
    int m = A.size();
    int n = A[0].size();
    vector<vector<int>> S(m + 1, vector<int>(n + 1, 0));
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) {
            S[i][j] = S[i - 1][j] + S[i][j - 1] - S[i - 1][j - 1] + A[i - 1][j - 1];
        }
    }
    return S;
}

// 查询子矩阵 [(x1, y1), (x2, y2)] 的和
int queryTwoDSum(const vector<vector<int>>& S, int x1, int y1, int x2, int y2) {
    return S[x2 + 1][y2 + 1] - S[x1][y2 + 1] - S[x2 + 1][y1] + S[x1][y1];
}

int main() {
    vector<vector<int>> A = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    vector<vector<int>> S = calculateTwoDPrefixSum(A);

    int x1 = 0, y1 = 0, x2 = 1, y2 = 1;
    cout << "The sum of the sub - matrix [(" << x1 << ", " << y1 << "), (" << x2 << ", " << y2 << ")] is: "
         << queryTwoDSum(S, x1, y1, x2, y2) << endl;

    return 0;
}

复杂度分析

  • 时间复杂度:计算二维前缀和矩阵需要两层嵌套循环遍历矩阵,时间复杂度为 O ( m × n ) O(m \times n) O(m×n)。每次查询子矩阵和的时间复杂度为 O ( 1 ) O(1) O(1),这使得在多次查询子矩阵和的场景下,二维前缀和算法非常高效。
  • 空间复杂度:需要额外的 ( m + 1 ) × ( n + 1 ) (m + 1)\times(n + 1) (m+1)×(n+1) 大小的矩阵来存储二维前缀和,因此空间复杂度为 O ( m × n ) O(m \times n) O(m×n)

通过以上的讲解和代码实现,我们可以看到前缀和算法在处理区间和与子矩阵和问题时的强大威力。它通过预处理的方式,将原本可能需要 O ( n ) O(n) O(n) O ( m × n ) O(m\times n) O(m×n) 时间复杂度的查询操作优化到了 O ( 1 ) O(1) O(1),在实际应用中能显著提升程序的性能。希望大家能够熟练掌握这两个模板,并在后续的算法学习和实践中灵活运用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2291322.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记8(高级API实现手写数字识别

目录 1、Keras&#xff1a;2、Sequential模型&#xff1a;2.1、建立Sequential模型&#xff1a;modeltf.keras.Sequential()2.2、添加层&#xff1a;model.add(tf.keras.layers.层)2.3、查看摘要&#xff1a;model.summary()2.4、配置训练方法&#xff1a;model.compile(loss,o…

88.[4]攻防世界 web php_rce

之前做过&#xff0c;回顾&#xff08;看了眼之前的wp,跟没做过一样&#xff09; 属于远程命令执行漏洞 在 PHP 里&#xff0c;system()、exec()、shell_exec()、反引号&#xff08;&#xff09;等都可用于执行系统命令。 直接访问index.php没效果 index.php?sindex/think\a…

23.Word:小王-制作公司战略规划文档❗【5】

目录 NO1.2.3.4 NO5.6​ NO7.8.9​ NO10.11​ NO12​ NO13.14 NO1.2.3.4 布局→页面设置对话框→纸张&#xff1a;纸张大小&#xff1a;宽度/高度→页边距&#xff1a;上下左右→版式&#xff1a;页眉页脚→文档网格&#xff1a;勾选只指定行网格✔→ 每页&#xff1a;…

数据结构 树1

目录 前言 一&#xff0c;树的引论 二&#xff0c;二叉树 三&#xff0c;二叉树的详细理解 四&#xff0c;二叉搜索树 五&#xff0c;二分法与二叉搜索树的效率 六&#xff0c;二叉搜索树的实现 七&#xff0c;查找最大值和最小值 指针传递 vs 传引用 为什么指针按值传递不会修…

玩转ChatGPT:DeepSeek测评(科研思路梳理)

一、写在前面 DeepSeek-R1出圈了&#xff0c;把OpenAI的o3-mini模型都提前逼上线了&#xff08;还免费使用&#xff09;。 都号称擅长深度推理&#xff0c;那么对于科研牛马的帮助有多大呢&#xff1f; 我连夜试一试。 二、科研思路梳理 有时候我们牛马们做了一堆结果以后&…

python学opencv|读取图像(五十三)原理探索:使用cv.matchTemplate()函数实现最佳图像匹配

【1】引言 前序学习进程中&#xff0c;已经探索了使用cv.matchTemplate()函数实现最佳图像匹配的技巧&#xff0c;并且成功对两个目标进行了匹配。 相关文章链接为&#xff1a;python学opencv|读取图像&#xff08;五十二&#xff09;使用cv.matchTemplate()函数实现最佳图像…

Linux环境下的Java项目部署技巧:安装 Mysql

查看 myslq 是否安装&#xff1a; rpm -qa|grep mysql 如果已经安装&#xff0c;可执行命令来删除软件包&#xff1a; rpm -e --nodeps 包名 下载 repo 源&#xff1a; http://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm 执行命令安装 rpm 源(根据下载的…

gitea - fatal: Authentication failed

文章目录 gitea - fatal: Authentication failed概述run_gitea_on_my_pkm.bat 笔记删除windows凭证管理器中对应的url认证凭证启动gitea服务端的命令行正常用 TortoiseGit 提交代码备注END gitea - fatal: Authentication failed 概述 本地的git归档服务端使用gitea. 原来的用…

计算机网络安全与运维的关键 —— 常用端口全解析

目录 前言 常见端口分类及用途 20 端口&#xff08;FTP 数据传输&#xff09; 21 端口&#xff08;FTP 消息控制&#xff09; 22 端口&#xff08;SSH&#xff09; 23 端口&#xff08;Telnet&#xff09; 25 端口&#xff08;SMTP&#xff09; 53 端口&#xff08;DNS&…

笔灵ai写作技术浅析(三):深度学习

笔灵AI写作的深度学习技术主要基于Transformer架构,尤其是GPT(Generative Pre-trained Transformer)系列模型。 1. Transformer架构 Transformer架构由Vaswani等人在2017年提出,是GPT系列模型的基础。它摒弃了传统的循环神经网络(RNN)和卷积神经网络(CNN),完全依赖自…

Linux-CentOS的yum源

1、什么是yum yum是CentOS的软件仓库管理工具。 2、yum的仓库 2.1、yum的远程仓库源 2.1.1、国内仓库 国内较知名的网络源(aliyun源&#xff0c;163源&#xff0c;sohu源&#xff0c;知名大学开源镜像等) 阿里源:https://opsx.alibaba.com/mirror 网易源:http://mirrors.1…

< OS 有关> BaiduPCS-Go 程序的 菜单脚本 Script: BaiduPCS-Go.Menu.sh (bdgo.sh)

目标&#xff1a; 使用 日本阿里云的 VPM 传输文件。 暂时方案&#xff1a; 使用 主机JPN 下载 https://huggingface.co/ 上模型从 JPN 放到 度狗上在家里从狗度下载 为了减少编程&#xff0c;尽量使用现在软件 &#xff0c;就找到 GitHub - qjfoidnh/BaiduPCS-Go: iikira…

【前端学习路线】前端优化 详细知识点学习路径(附学习资源)

&#x1f4da;学习资源&#xff1a; 前端开发&#xff1a;零基础入门到项目实战 >> 前端开发&#xff1a;边学边练 >> 原学习路径下载 >>

【零拷贝】

目录 一&#xff1a;了解IO基础概念 二&#xff1a;数据流动的层次结构 三&#xff1a;零拷贝 1.传统IO文件读写 2.mmap 零拷贝技术 3.sendFile 零拷贝技术 一&#xff1a;了解IO基础概念 理解CPU拷贝和DMA拷贝 ​ 我们知道&#xff0c;操作系统对于内存空间&…

扩散模型(一)

在生成领域&#xff0c;迄今为止有几个主流的模型&#xff0c;分别是 GAN, VAE&#xff0c;Flow 以及 Diffusion 模型。 GAN&#xff1a;GAN 的学习机制是对抗性学习&#xff0c;通过生成器和判别器的对抗博弈来进行学习&#xff0c;这种竞争机制促使生成器不断提升生成能力&a…

【LLM-agent】(task6)构建教程编写智能体

note 构建教程编写智能体 文章目录 note一、功能需求二、相关代码&#xff08;1&#xff09;定义生成教程的目录 Action 类&#xff08;2&#xff09;定义生成教程内容的 Action 类&#xff08;3&#xff09;定义教程编写智能体&#xff08;4&#xff09;交互式操作调用教程编…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.12 连续数组:为什么contiguous这么重要?

2.12 连续数组&#xff1a;为什么contiguous这么重要&#xff1f; 目录 #mermaid-svg-wxhozKbHdFIldAkj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wxhozKbHdFIldAkj .error-icon{fill:#552222;}#mermaid-svg-…

O3 模型正式上线,能否与 DeepSeek 一较高下?

OpenAI 最近推出了 GPT O3 模型&#xff0c;并对 ChatGPT Plus 用户的 O3-mini 版本进行了升级&#xff0c;提升了每日消息限额&#xff0c;从 50 条增加至 150 条。这一调整大大提升了用户体验&#xff0c;让更多用户有机会深入体验 O3 模型的能力。那么&#xff0c;O3 模型的…

计算机网络 应用层 笔记1(C/S模型,P2P模型,FTP协议)

应用层概述&#xff1a; 功能&#xff1a; 常见协议 应用层与其他层的关系 网络应用模型 C/S模型&#xff1a; 优点 缺点 P2P模型&#xff1a; 优点 缺点 DNS系统&#xff1a; 基本功能 系统架构 域名空间&#xff1a; DNS 服务器 根服务器&#xff1a; 顶级域…

MATLAB的数据类型和各类数据类型转化示例

一、MATLAB的数据类型 在MATLAB中 &#xff0c;数据类型是非常重要的概念&#xff0c;因为它们决定了如何存储和操作数据。MATLAB支持数值型、字符型、字符串型、逻辑型、结构体、单元数组、数组和矩阵等多种数据类型。MATLAB 是一种动态类型语言&#xff0c;这意味着变量的数…