【前缀和算法】--- 一维和二维前缀和模板

2024-08-20 23:36

本文主要是介绍【前缀和算法】--- 一维和二维前缀和模板,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 Welcome to 9ilk's Code World

       

(๑•́ ₃ •̀๑) 个人主页:       9ilk

(๑•́ ₃ •̀๑) 文章专栏:    算法Journey  


本文开始,博主开始讲解有关前缀和的算法,本篇博客我们先来了解一下有关前缀和的两个模板。


🏠 一维前缀和模板

📌 题目内容

一维前缀和

📌题目解析

  • 数组的下标是从1开始的。
  • 数组中每个值的范围是−10^9 ≤ a[i] ≤ 10^9,因此我们需要考虑如果多个值相加用int可能溢出,可以考虑用long long.

📌算法原理

✏️ 思路一:暴力解法

 暴力解法很简单就是进行模拟,每次查询从L下标开始遍历直到到R下标。最坏情况是L是1下标,而R是n下标,n为数组长度。因此时间复杂度为O(q*n).

有没有什么优化的解法?

✏️ 思路二:前缀和

前缀和算tg法分为两步:1.预处理出来一个前缀和数组。2.使用前缀和数组。它可以用来快速求出数组中某一个连续区间的和。

  • 预处理出前缀和数组

假设有一个数组arr,同时有个相关联的数组dp,dp[i]表示的是arr数组[1,i]区间内所有值和。

我们发现,比如dp[3]是【1,3】区间值的和,那么就相当于是【1,2】区间的和+arr[3].

因此我们可以得出公式dp[i] = dp[i-1] + arr[i].

通过公式我们在遍历一遍数组的同时,就可以求出前缀和数组。

  • 使用前缀和数组

题目要我们求出[l,r]区间内值的和,由于我们提前求出了前缀和数组,我们发现所求区间 = 总和 - 前一段区间,因此【l,r】= dp[r] - dp[l-1],这个过程是很快的达到了O(1)

参考代码:

typedef long long ll;
int main() 
{int n = 0;int q = 0; //查询次数cin >> n >> q;vector<ll> v(n+1,0);vector<ll> dp(n+1,0);ll prev = 0;//获得前缀和数组//dp[i]表示的是从1到i区间值的总和for(int i = 1 ; i <= n ; i++){cin >> v[i];dp[i] = dp[i-1] + v[i];} //使用前缀和数组while(q--){int l = 0;int r = 0;cin >> l >> r;cout << dp[r] - dp[l-1] << endl; }return 0;
}
  • 细节问题

我们前缀和数组下标是从1开始的,如果下标从0开始,当求[0,2]区间的值之和时就转化成dp[2] - dp[-1]这个dp[-1]是个边界情况需要我们特殊处理且原本数组没有-1开始的;如果下标从1开始,当求[1,2]区间的值之和时转化成dp[2] - dp[0],对于dp[0]我们就容易将它处理为0即可

总结:前缀和数组下标从1开始,是为了处理边界情况。

🏠 二维前缀和数组

📌 题目内容

二维前缀和

📌 题目解析

  • 本题数据范围仍然过大,用int会有溢出的风险。
  • 题目要我们求的是以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的和。

📌 算法原理

✏️ 思路一:暴力解法

暴力解法也就是模拟从第一个点开始直接按照划分区域进行遍历,最坏情况是整个矩阵,时间复杂度是O(n*m*q).

✏️ 思路二:二维前缀和

  • 预处理出二维前缀和数组

假设有一个二维数组arr,dp数组是一个与它关联的数组。dp[i][j]表示以(1,1)为左上角,(i,j)为右上角形成的子矩阵中值之和。任取一块区域,假设D为(i,j)点,若我们要求dp[i][j]也就是求(1,1)到(i,j)区域的和,我们可以将这四部分相加,由于B和C不好求,我们可以利用A(dp[i-1][j-1])来间接求这两部分,但是不要忘记减去多进来的A。由于A+B和A+C在dp数组中分别对应的是dp[i-1][j]和dp[i][j-1],因此我们可以得到公式:

dp[ i ][ j ] = dp[ i-1 ][ j ] + dp[ i ][ j-1 ] + arr[ i ][ j ] - dp[ i-1][ j-1 ].

通过公式,我们在遍历二维数组时就可以求出对应的dp二维数组。

  • 使用二维前缀和数组

题目要我们求以(x1,y1)为左上角,(x2,y2)为右上角区域的值之和,也就是求区域D。因此D可以由整体减去A,B,C三部分,由于B和C不好求,所以我们利用A间接求。于是有D=(A+B+C+D) - (A+C) - (A+B) +A。对于A就是dp[x1][y1],A+B就是dp[x1-1][y2],A+C就是dp[x2][y1-1],于是得到公式:D = dp[x2][y2] - dp[x2][y1-1] - dp[x1-1][y2] + dp[x1-1][y1-1]。此时 我们由于提前得到的二维前缀和数组,我们能很快得出D的值,时间复杂度是O(1).

时间复杂度优化为了O(m*n) + O(q).

参考代码:

int main() 
{int n = 0; //行 int m = 0; //列int q = 0; //查询次数cin >> n >> m >> q;vector<vector<long long>> vv(n + 1);vector<vector<long long>> dp(n + 1);for (int i = 0; i <= n; i++){vv[i].resize(m + 1, 0);dp[i].resize(m + 1, 0);if (i >= 1){for (int j = 1; j <= m; j++){cin >> vv[i][j];}}}for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++){dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + vv[i][j] - dp[i-1][j-1];}}while (q--){int x1, x2, y1, y2 = 0;cin >> x1 >> y1 >> x2 >> y2;cout << dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1] << endl;}return 0;
}

总结:

1. 一维和二维前缀和数组下标都是从1开始。

2.当我们需要快速求出一段连续区间或区域时,可以考虑用前缀和数组,用前缀和数组间接求我们需要的。

3.我们可以根据场景推导出公式获得前缀和数组。

这篇关于【前缀和算法】--- 一维和二维前缀和模板的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

正则表达式r前缀使用指南及如何避免常见错误

《正则表达式r前缀使用指南及如何避免常见错误》正则表达式是处理字符串的强大工具,但它常常伴随着转义字符的复杂性,本文将简洁地讲解r的作用、基本原理,以及如何在实际代码中避免常见错误,感兴趣的朋友一... 目录1. 字符串的双重翻译困境2. 为什么需要 r?3. 常见错误和正确用法4. Unicode 转换的

Java如何根据word模板导出数据

《Java如何根据word模板导出数据》这篇文章主要为大家详细介绍了Java如何实现根据word模板导出数据,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... pom.XML文件导入依赖 <dependency> <groupId>cn.afterturn</groupId>

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Java如何根据文件名前缀自动分组图片文件

《Java如何根据文件名前缀自动分组图片文件》一大堆文件(比如图片)堆在一个目录下,它们的命名规则遵循一定的格式,混在一起很难管理,所以本文小编就和大家介绍一下如何使用Java根据文件名前缀自动分组图... 目录需求背景分析思路实现代码输出结果知识扩展需求一大堆文件(比如图片)堆在一个目录下,它们的命名规

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

Python中Flask模板的使用与高级技巧详解

《Python中Flask模板的使用与高级技巧详解》在Web开发中,直接将HTML代码写在Python文件中会导致诸多问题,Flask内置了Jinja2模板引擎,完美解决了这些问题,下面我们就来看看F... 目录一、模板渲染基础1.1 为什么需要模板引擎1.2 第一个模板渲染示例1.3 模板渲染原理二、模板

利用Python打造一个Excel记账模板

《利用Python打造一个Excel记账模板》这篇文章主要为大家详细介绍了如何使用Python打造一个超实用的Excel记账模板,可以帮助大家高效管理财务,迈向财富自由之路,感兴趣的小伙伴快跟随小编一... 目录设置预算百分比超支标红预警记账模板功能介绍基础记账预算管理可视化分析摸鱼时间理财法碎片时间利用财

如何在 Spring Boot 中实现 FreeMarker 模板

《如何在SpringBoot中实现FreeMarker模板》FreeMarker是一种功能强大、轻量级的模板引擎,用于在Java应用中生成动态文本输出(如HTML、XML、邮件内容等),本文... 目录什么是 FreeMarker 模板?在 Spring Boot 中实现 FreeMarker 模板1. 环

IDEA自动生成注释模板的配置教程

《IDEA自动生成注释模板的配置教程》本文介绍了如何在IntelliJIDEA中配置类和方法的注释模板,包括自动生成项目名称、包名、日期和时间等内容,以及如何定制参数和返回值的注释格式,需要的朋友可以... 目录项目场景配置方法类注释模板定义类开头的注释步骤类注释效果方法注释模板定义方法开头的注释步骤方法注

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a