初识算法 · 前缀和(1)

news2024/10/27 7:40:49

目录

前言:

一维数组的前缀和

题目解析

算法原理

算法编写

二维数组的前缀和

题目解析

算法原理

算法编写


前言:

​本文的主题是前缀和,通过两道题目讲解,一道是一维数组的模板,一道是二维数组的模板。
链接分别为:
【模板】前缀和_牛客题霸_牛客网
【模板】二维前缀和_牛客题霸_牛客网
题目分为三个部分讲解,一是题目解析,二是算法原理,三是算法编写,那么,话不多说,直接进行主题咯。


一维数组的前缀和

题目解析

题目看起来是较为复杂的,一共需要输入四个数,输入的n代表的是这个数组的长度,q代表的是查询的次数,l 和 r代表的是下标,输出的是数组arr[l] + …… + arr[r]。

那么这里就是有疑问的,题目描述的为什么是从a[1]到a[n]?而不是从arr[0]开始呢?

这里是为了防止边界,我们在算法原理部分介绍。

我们首先思考暴力解法,暴力解法无非就是模拟这个相加的过程,那么时间复杂度是查询次数 * (l - r + 1),所以最坏的情况就是l是1,r是n,所以时间复杂度就是q * n。

在这里,时间肯定是过不了的,因为题目要求:

所以q * n的话,时间复杂度是10^5,放在任何一道编程题都是过不去的。

那么我们的前缀和算法就闪亮登场了。

算法原理

这道题目我们使用的是前缀和数组,那么什么是前缀和呢?

前缀和数组,无非就是dp[i]代表的是从arr[0]一直加到arr[i],这个数组的使用在这里已经很接近我们使用该数组的本意了。

使用该数组为了简化我们暴力遍历数组这个过程。

那么对于l r来说,我们要求的是arr[l] + …… + arr[r],所以这个过程我们可以使用前缀和数组简化成dp[r] - dp[l - 1],那么这个过程是O(1)的,也就是整体下来时间复杂度是q的。

但是为什么索引是从1开始的呢?这是为了处理边界情况,如果我们要求的是 0 2这个区间,那么l - 1的值就是-1,对于一个数组来说肯定是访问不了-1的,所以这道题是从1开始的。

这是一个小细节。

算法编写

#include <iostream>
#include <vector>
using namespace std;

int main() 
{
    //1.输入数据
    int n = 0, q = 0;
    cin >> n >> q;
    vector<int> arr(n + 1, 0);
    for(int i = 1;i <= n; i++) 
        cin >> arr[i];

    //2.预处理前缀和数组
    vector<long long> dp(n + 1, 0);
    for(int i = 1; i <= n; i++)
        dp[i] = dp[i - 1] + arr[i];

    //3.使用前缀和数组
    int l = 0, r = 0;
    while(q--)
    {
        cin >> l >> r;
        cout << dp[r] - dp[l - 1] << endl;
    }
    return 0;
}

但是这道题目有个坑就是,如果两个整型相加可能会导致溢出的问题,所以dp数组使用的long long类型。

这是一维数组的模板,下一道题目是二维数组的模板。


二维数组的前缀和

题目解析

题目的要求和一维数组是差不多的,但是并不是从1一直加到n的,而是一个区域:

就像这样,输入的x1 y1 x2 y2是1 1  2 2,那么要求的值就是由这几个下标组成的正方形的值。

当然了,暴力解法的话,肯定是要超时的,所以我们就不予考虑了。

题目的要求我们也是基本清楚了,并且在牛客上的时候,会提示使用lld打印,所以存在溢出的风险,第二个数组就使用long long类型了。

我们就直接介绍二维数组前缀和的算法原理了。

算法原理

对于二维数组前缀和的算法原理部分,同理,我们就需要得到i j对应的区域大小了:

我们如果直接遍历的话,就和暴力解法没有什么区别,所以我们不如拆分一下这个二维数组,对于dp[i][j]来说的话,就是从1 1的位置到i j位置,我们可以划分成四个区域,A B C D,如果单独求A B C的大小并不是很好求的,所以我们不妨变动一下式子,改成A + B + A + C + D - A。

此时A + B就是dp[i - 1][j] A + C 就是等于dp[i][j - 1],D就是arr[i][j],A就是dp[i - 1][j - 1]。

得到dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + arr[i][j] - dp[i - 1][j - 1]。

预处理前缀和数组就结束了,接下来是如何使用的问题。

给的是x1 y1 x2 y2,题目要求的值就是D。同样的,如果我们直接硬求每个区域的值,非常麻烦,所以我们不妨变化一下式子 D = A + B + C + D - (A + B) - (A + C) + A。至于为什么这样干,因为我们发现如果单独求B或者C十分麻烦,所以用来和A结合一下。

此时对于A + B + C + D,就是dp[x2][y2],对于A + C来说,就是dp[x2][y1 - 1],对于A + B来说,就是dp[x1 - 1][y2],A就是dp[x1 - 1][y1 - 1]。

使用前缀和结束了,这道题目也就结束了。

算法编写

#include <iostream>
#include <vector>
using namespace std;

int main() 
{
    //1.输入数据
    int n = 0, m = 0, q = 0;
    cin >> n >> m >> q;
    vector<vector<int>> arr(n + 1, vector<int>(m + 1));
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            cin >> arr[i][j];

    //2.预处理前缀和数组
    vector<vector<long long>> dp(n + 1, vector<long long>(m + 1));
    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] + arr[i][j] - dp[i - 1][j - 1];

    //3.使用前缀和数组
    int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
    while(q--)
    {
        cin >> x1 >> y1 >> x2 >> y2;
        cout << dp[x2][y2] - dp[x2][y1 - 1] - dp[x1 - 1][y2] + dp[x1 - 1][y1 - 1] << endl;
    }
    return 0;
}

前缀和的模板就介绍完毕了~


感谢阅读!

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

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

相关文章

03 文件管理和IO重定向

1 文件系统目录结构 1.1 文件系统目录结构 文件系统的目录结构成树形结构一切文件的路径起点都是从根目录开始&#xff0c;用 / 表示文件名大小写敏感以 . 开头的文件都是隐藏文件路径通过 / 进行分割不同颜色的文件&#xff0c;它的类型是不同的每个文件都有两类数据&#xff…

S-Function

目录 S-Function介绍 生成S-Function的三种常用手段 使用手写S-函数合并定制代码 使用S-Function Builder块合并定制代码 使用代码继承工具合并定制代码 S-Function介绍 我们可以使用S-Function扩展Simulink对仿真和代码生成的支持。例如&#xff0c;可以使用它们&#xf…

初识Linux · 动静态库(incomplete)

目录 前言&#xff1a; 静态库 动态库 前言&#xff1a; 继上文&#xff0c;我们从磁盘的理解&#xff0c;到了文件系统框架的基本搭建&#xff0c;再到软硬链接部分&#xff0c;我们开始逐渐理解了为什么运行程序需要./a.out了&#xff0c;这个前面的.是什么我们也知道了。…

探索 Python 幽默之源:pyjokes 库全解析

&#x1f680; 探索 Python 幽默之源&#xff1a;pyjokes 库全解析 1. 背景介绍&#xff1a;为何选择 pyjokes&#xff1f; 在紧张的编程工作中&#xff0c;幽默是一种有效的缓解压力的方式。pyjokes 是一个专为程序员设计的 Python 库&#xff0c;它提供了丰富的单行笑话&am…

vscode配色主题与图标库推荐

vscode配色主题推荐:Andromedavsocde图标库&#xff1a; vscode-icons Andromeda Dark theme with a taste of the universe 仙女座&#xff1a;一套宇宙深空体验的哑暗色主题; 高对比度,色彩饱和; Easy Installation Open the extensions sidebar on Visual Studio CodeSear…

定时任务使用kafka

定时任务使用kafka 在上述业务场景中使用 Kafka 而不是直接定时执行任务有以下几个重要原因&#xff1a; 一、解耦 任务触发与执行分离&#xff1a; 使用 XXL-JOB 定时触发任务并将任务消息发送到 Kafka&#xff0c;实现了任务触发端&#xff08;通常是调度系统&#xff09;和…

C++,STL 049(24.10.26)

内容 pair的基本概念及构建方式。 运行代码 #include <iostream> #include <string>using namespace std;void test01() {// pair将2个数据组合成一组数据来使用&#xff08;first 、second&#xff09;// 注意pair的使用可以不添加头文件pair<string, int>…

Golang | Leetcode Golang题解之第501题二叉搜索树中的众数

题目&#xff1a; 题解&#xff1a; func findMode(root *TreeNode) (answer []int) {var base, count, maxCount intupdate : func(x int) {if x base {count} else {base, count x, 1}if count maxCount {answer append(answer, base)} else if count > maxCount {ma…

实验干货|电流型霍尔传感器采样设计02-有源滤波设计

在上一篇博客中&#xff0c;介绍了如何通过跨阻放大器&#xff0c;将霍尔输出的电流转换成电压。本篇博客继续介绍&#xff0c;如何将得到的电压进行滤波。 有源滤波和无源滤波的选择 简单来说&#xff0c;对于采样电路而言&#xff0c;无源滤波一般选择RC滤波&#xff0c;RC…

【K8S系列】Kubernetes Service 基础知识 详细介绍

在 Kubernetes 中&#xff0c;Service 是一种抽象的资源&#xff0c;用于定义一组 Pod 的访问策略。它为这些 Pod 提供了一个稳定的访问入口&#xff0c;解决了 Pod 可能频繁变化的问题。本文将详细介绍 Kubernetes Service 的类型、功能、使用场景、DNS 和负载均衡等方面。 1.…

使用FRP搭建内网穿透服务(新版toml配置文件,搭配反向代理方便内网网站访问)【使用frp搭建内网穿透】

FRP&#xff08;Fast Reverse Proxy&#xff09;是一个高性能的反向代理应用程序&#xff0c;主要用于内网穿透。它允许用户将内部网络服务暴露到外部网络&#xff0c;适用于 NAT 或防火墙环境下的服务访问。 他是一个开源的 服务 如果大家不想用 花生壳 软件&#xff0c;可以尝…

遗传算法(Genetic Algorithm)理论详解

遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;是一种模拟自然界生物进化过程与机制的随机搜索与优化算法&#xff0c;被广泛应用于计算机科学、工程技术、经济学等众多领域。 1. 基本原理 1.1 生物遗传学类比 遗传算法的灵感来源于达尔文的进化论。在自然…

订购 Claude AI 的第二天 它独自完成 文字转语音 flask应用

图二里&#xff0c;删除几个无关的 chats 全程我做的工作&#xff1a;向 AI 提要求&#xff0c;copy / paste 代码&#xff0c;在venv验证运行&#xff0c;向 AI 反馈&#xff0c;总共用了3个 chats.&#xff08;图中的只有一个 Chat&#xff0c; 删掉的另外两个: Python 库安…

背包问题(位运算优化、bitset)

3180. 执行操作可获得的最大总奖励| . - 力扣&#xff08;LeetCode&#xff09; 给你一个整数数组 rewardValues&#xff0c;长度为 n&#xff0c;代表奖励的值。 最初&#xff0c;你的总奖励 x 为 0&#xff0c;所有下标都是 未标记 的。你可以执行以下操作 任意次 &#xf…

数字IC后端实现 | Innovus各个阶段常用命令汇总

应各位读者要求&#xff0c;小编最近按照Innovus流程顺序整理出数字IC后端项目中常用的命令汇总。限于篇幅&#xff0c;这次只更新到powerplan阶段。有了这份Innovus常用命令汇总&#xff0c;学习数字IC后端从此不再迷路&#xff01;如果大家觉得这个专题还不错&#xff0c;想继…

Linux 字符设备驱动 之 无法归类的《杂项设备驱动》

学习目标&#xff1a; 了解 杂项设备驱动 和普通字符设备的异同&#xff0c;及杂项设备驱动程序的写法 学习内容&#xff1a; 一、杂项设备驱动的特别之处 杂项设备&#xff08;Miscellaneous Devices&#xff09;是一种通用的设备类型&#xff0c;用于表示那些不适合其他设备…

LeetCode 热题 100之普通数组

1.最大子数组和 思路分析&#xff1a;这个问题可以通过动态规划来解决&#xff0c;我们可以使用Kadane’s Algorithm&#xff08;卡登算法&#xff09;来找到具有最大和的连续子数组。 Kadane’s Algorithm 的核心思想是利用一个变量存储当前的累加和 currentSum&#xff0c;并…

Prometheus自定义PostgreSQL监控指标

本文我们将介绍如何在Prometheus中创建自定义PostgreSQL指标。默认情况下由postgres_export运行的查询可能不能满足用户需求&#xff0c;但我们可以创建自定义查询&#xff0c;并要求postgres_exporter公开自定义查询的结果。postgres_exporter最近被移到了Prometheus Communit…

acwing排列数字

排列数字 给定一个整数 n&#xff0c;将数字 1∼n排成一排&#xff0c;将会有很多种排列方法。 现在&#xff0c;请你按照字典序将所有的排列方法输出。 输入格式 共一行&#xff0c;包含一个整数 n。 输出格式 按字典序输出所有排列方案&#xff0c;每个方案占一行。 数…

lvs知识点归纳

LVS&#xff08;Linux Virtual Server&#xff09;是 Linux 内核的一种负载均衡技术&#xff0c;主要用于实现高可用性和高性能的服务器集群。以下是一些关键知识点的归纳&#xff1a; 基本概念 虚拟服务器&#xff1a;将多台物理服务器&#xff08;真实服务器&#xff09;抽象…