【优选算法专栏】专题四:前缀和(一)

本专栏内容为:算法学习专栏,分为优选算法专栏,贪心算法专栏,动态规划专栏以及递归,搜索与回溯算法专栏四部分。 通过本专栏的深入学习,你可以了解并掌握算法。

💓博主csdn个人主页:小小unicorn
⏩专栏分类:算法从入门到精通
🚚代码仓库:小小unicorn的代码仓库🚚
🌹🌹🌹关注我带你学习编程知识

专题四

  • 前缀和
    • 算法原理:
      • 解法一:
      • 解法二:
  • 二维前缀和
    • 算法原理:

前缀和

在这里插入图片描述

算法原理:

我们先分析一下题目:
在这里插入图片描述
题目的意思是求给定区间的和,区间由用户决定。

解法一:

看到这个题目,我们首先想到的是暴力+枚举来解决这个情况。
在这里插入图片描述
把所有询问q次的子数组都枚举出来,但是题目给的数据很大,肯定会超时。因为每q次询问都要把整个数组遍历一遍,因此时间复杂度为 n ∗ q n*q nq

在此基础上我们可以进行优化:

解法二:

解法二就是我们要介绍的前缀和知识。

前缀和是什么?首先我们要知道一点:前缀和可以快速求出数组中某一个连续区间的和。其次前缀和可以降低时间复杂度,对于本题而言,暴力+枚举时间复杂度达到了 n ∗ q n*q nq而利用前缀和进行优化就可降低到 q q q;

前缀和分两步:

  1. 预处理一个前缀和数组:
  2. 使用前缀和数组

第一步:
什么是一个前缀和数组?我们要先明确一点,其实前缀和就是一个简单的动态规划。我们首先创一个dp数组(下标数组)。这个数组i位置的值代表从[1,i]区间内所有元素的和。也就是说:

dp[i]表示从[1,i]区间内所有元素的和

接下来我们分析一下递推:
注意数组的下标是从1开始而不是从0开始。
在这里插入图片描述
arr数组为原数组,dp[2]的值代表原数组区间[1,2]内元素的和,也就是5,dp[3]的值为原数组前三个数相加的结果,那么dp[4]就是原数组前4个数相加的结果,但是从dp数组的第三个位置开始,我们也可以是dp[2]+上原始第三个位置的值,也就是 d p [ 3 ] = d p [ 2 ] + a r r [ 3 ] dp[3]=dp[2]+arr[3] dp[3]=dp[2]+arr[3];依次内推最后一个元素的位置就是 d p [ i ] = d p [ i − 1 ] + a r r [ i ] dp[i]=dp[i-1]+arr[i] dp[i]=dp[i1]+arr[i];

d p [ i ] = d p [ i − 1 ] + a r r [ i ] dp[i]=dp[i-1]+arr[i] dp[i]=dp[i1]+arr[i]就是我们要找的递推关系式子,而其实这个式子也可以称为动态规划里面的状态转移方程。
在这里插入图片描述
预处理做好后,接下来就是第二步:

我们应该如何使用前缀和数组呢?
我们先分析一下:
在这里插入图片描述
现在我们的dp数组里面存放的值分别是从1位置开始到i位置结束该区间所有元素的和。那么我们如何求里面具体某一段的和呢?
在这里插入图片描述
其实很简单,就比如我们要求[3,5]区间的和,我们[1,5]的和是知道的,[1.2]的和是知道的,我们用[1,5]区间的和-去[1,2]的和不就是我们所求的吗?
我们抽象出来,l和r,那么[l,r]区间的和就是 d p [ r ] − d p [ l − 1 ] dp[r]-dp[l-1] dp[r]dp[l1]

介绍到这,我们一维前缀和知识基本上差不多了,但是还有个小问题,别忘了我们数组下标是从1开始的,为什么不从0开始呢?这其实就是为了防止边界情况。
在这里插入图片描述
假设我们要求的区间是[0,2]那么对用我们的递推式:
dp[2]-dp[-1],就会产生越界,这里就需要我们对边界情况做特殊处理。

代码实现:

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

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

    //2.预处理出来一个前缀和数组
    vector<long long > dp(n+1);
    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二位数组里面放的是某区间的和。那么我们的
dp[i][j]就表示:从[1,1]位置到[i][j]位置,这段区间内所有元素的和。

一维好说,这二维看着和想求出来不简单啊,既然直接求不来,那么我们就去而求其次。

咱们把整个面积分成四块:A,B,C,D

在这里插入图片描述
那么我们的 d p [ i ] [ j ] = A + B + C + D dp[i][j]=A+B+C+D dp[i][j]=A+B+C+D;
柿子先挑软的捏,D区域肯定是我们最好求的,D区域对应原数组不就是arr[i];不仅如此,A也可以求,A区域为dp[i-1][j-1];

B和C怎么求呢?
既然不好求那干脆我们不求,我们换个角度看:AB区域和AC区域其实很好求,然后看整体:
我们要求整个面积可以这样求:
( A + B ) + ( A + C ) + D − A (A+B)+(A+C)+D-A (A+B)+(A+C)+DA

在这里插入图片描述
分析到这,我们的递推关系式其实已经出来了:
d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] + a r r [ i ] [ j ] − d p [ i − 1 ] [ j − 1 ] dp[i][j]=dp[i-1][j]+dp[i][j-1]+arr[i][j]-dp[i-1][j-1] dp[i][j]=dp[i1][j]+dp[i][j1]+arr[i][j]dp[i1][j1]

接下来就是第二步:
如何使用:
其实分析到这,使用二维前缀和数组肯定也是要间接求:
给定区间求[x1,y1]到[x2,y2]区间内的和,也就是求D区域。从左上角绿格子到右下角绿格子的这部分区域的值。D区域可以将整个分为4部分A,B,C,D
在这里插入图片描述

那么我们的D可以这样求:
在这里插入图片描述

D = A + B + C + D − ( A + B ) − ( A + C ) + A D=A+B+C+D-(A+B)-(A+C)+A D=A+B+C+D(A+B)(A+C)+A
那么我们的递推是也就出来了
d p [ x 2 , y 2 ] − d p [ x 1 − 1 ] [ y 2 ] − d p [ x 2 ] [ y 1 − 1 ] + d p [ x 1 − 1 ] [ y 1 − 1 ] dp[x2,y2]-dp[x1-1][y2]-dp[x2][y1-1]+dp[x1-1][y1-1] dp[x2,y2]dp[x11][y2]dp[x2][y11]+dp[x11][y11]

代码实现:

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

int main()
{
    //1.输入数据
    int n=0,m=0,q=0;
    cin>>n>>m>>q;
    vector<vector<long long>> arr(n+1,vector<long long>(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,y1,x2,y2;
    while(q--)
    {
        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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

还不会免费将PDF转为Word?赶快试试这3种工具!

PDF文档格式转换是高频且刚需的办公需求&#xff0c;虽然很简单&#xff0c;但其实绝大部分人找不到合适的工具。 将PDF免费转为Word的方法有很多&#xff0c;这里主要介绍三种工具。 第一种使用最常见的Word软件&#xff0c;第二种使用免费转换网站pdf2doc&#xff0c;第三种…

cmocka入门教程

文章目录 摘要前言什么是mockmock示例cmocka安装使用mock function替换subfunction控制mock function的输入和输出 摘要 本文介绍cmocka中&#xff0c;mock的使用。 前言 在这之前&#xff0c;需要了解最基本的cmocka使用。如果之前有gtest的编程经验&#xff0c;掌握cmocka的…

蓝桥杯 迷宫(bfs)

0迷宫 - 蓝桥云课 (lanqiao.cn) 思路 &#xff1a; 最后一定要倒数输出路径&#xff0c;因为从前面输出你会找不到下一个到底是谁&#xff0c;bfs过程是找最小路径&#xff0c;最后输出是去找方向&#xff0c;但是此题作为一个填空题&#xff0c;我直接手写&#xff08;开玩笑…

对于Redis,如何根据业务需求配置是否允许远程访问?

1、centos8 Redis安装的配置文件目录在哪里&#xff1f; 在 CentOS 8 中&#xff0c;默认情况下 Redis 的配置文件 redis.conf 通常位于 /etc/ 目录下。确切的完整路径是 /etc/redis.conf。 2、redis如何设置允许远程登录 修改redis.conf文件 # 继承默认注释掉的bind配置 # …

十种mfc140.dll丢失的解决方法,有效解决mfc140.dll丢失的问题

唉&#xff0c;烦人的问题又来了。怎么计算机报错提示mfc140.dll无法启动&#xff1f;这mfc140.dll是何方神圣&#xff0c;竟然连软件程序的正常运行都能影响到&#xff1f;我猜你也被这种困扰搞得头大吧。别着急&#xff0c;下面我会详细分享mfc140.dll丢失时的修复步骤&#…

Android平台RTSP|RTMP播放器如何实现TextureView渲染

技术背景 自2015年我们发布Android平台RTSP、RTMP直播播放模块以来&#xff0c;渲染这块&#xff0c;支持SurfaceView或GlSurfaceView&#xff0c;当然如果开发者需要TextureView渲染&#xff0c;可以把RTSP、RTMP流数据解码回调YUV或RGB数据上来&#xff0c;上层自己渲染。本…

pycharm一直打不开

一直处在下面的页面&#xff0c;没有反应 第一种方案&#xff1a; 以管理员身份运行 cmd.exe&#xff1b;在打开的cmd窗口中&#xff0c;输入 netsh winsock reset &#xff0c;按回车键&#xff1b;重启电脑&#xff1b;重启后&#xff0c;双击pycharm图标就能打开了&#xf…

阿里淘天一面凉经

电话面&#xff0c;秒挂。 由于答的依托。导致面试官一开始就准备要挂我了。后面问的参考性不大。 总结&#xff1a; 1.自我介绍 2.项目里自己体会比较多的&#xff0c;遇到困难比较大的技术实现。&#xff08;没复习&#xff09; 3.项目中什么场景下用到分布式锁&#xf…

提升Terraform工作流程最佳实践

Terraform 是管理基础设施及代码&#xff08;IaC&#xff09;最常用的工具之一&#xff0c;它能使我们安全且可预测地对基础设施应用更改。刚开始上手 Terraform 可能会感觉有些不容易&#xff0c;但很快就能对该工具有基本的了解&#xff0c;随之可以开始运行命令、创建和重构…

如何压缩视频?5种超简单的方法!

用视频来记录生活和重要信息变得越来越广泛&#xff0c;比如用手机拍摄美好瞬间、对线上会议或课堂的内容进行视频录制、保存各种精彩的电影文件、社交媒体上分享美好生活&#xff0c;但是由于视频本身包含的信息很多以及拍摄设备的进步&#xff0c;文件越来越大&#xff0c;占…

08 Php学习:iff语句、Switch语句

PHP 条件语句 当您编写代码时&#xff0c;您常常需要为不同的判断执行不同的动作。您可以在代码中使用条件语句来完成此任务。 在 PHP 中&#xff0c;提供了下列条件语句&#xff1a; if 语句 - 在条件成立时执行代码 if…else 语句 - 在条件成立时执行一块代码&#xff0c;…

FreeRTOS任务切换学习

FreeRTOS任务切换学习 所谓任务切换&#xff0c;就是CPU寄存器的切换。假设当由任务A切换到任务B时&#xff0c;主要分为两步&#xff1a; 1&#xff1a;需暂停任务A的执行&#xff0c;并将此时任务A的寄存器保存到任务堆栈&#xff0c;这个过程叫做保存现场&#xff1b; 2&am…

【STL】list

目录 1. list的使用 1.1 list的构造 1.2 list iterator的使用 1.3 list capacity 1.4 list element access 1.5 list modifiers 1.6 list的迭代器失效 2. list的模拟实现 3. list与vector的对比 1. list的使用 1.1 list的构造 1.2 list iterator的使用 1. begin与end为…

雨污管网开挖深度的计算

一般的管网工程都有纵断面设计图&#xff0c;结合纵断面里的 管内底埋深-管厚度(直径0.6管厚0.06&#xff0c;直径0.8承插管直径0.08厚) - 砂砾石基础一般0.15厚 - 路面结构层厚度就是沟槽开挖深度了&#xff0c;是不是很简单。 管内底埋深其实就是管内流水面到设计路面顶的高…

PyCharm+PyQt5配置方法

一、前言 PyQt5PyQt5是一套Python绑定Digia QT5应用的框架。Qt库是最强大的GUI库之一PyQt5-toolsPyQt5中没有提供常用的Qt工具&#xff0c;比如图形界面开发工具Qt Designer&#xff0c;PyQt5-tools中包含了一系列常用工具Qt Designer可以通过Qt Designer来编写UI界面&#xf…

Docker快速上手及常用命令速查

Docker快速上手 安装 在ubuntu上安装docker: sudo apt-get install docker docker -v #查看版本在centos7上安装docker&#xff1a;(docker在YUM源的Extras仓库中) yum install docker systemctl start dockerdocker常用命令速查 #查看docker信息 docker info #查看本地镜…

网络基础三——其他周边问题

3.1ARP原理 ​ ARP不是一个单纯的数据链路层的协议&#xff0c;而是一个介于数据链路层和网络层之间的协议&#xff1b; ​ 以广播的形式(主机号填成全1)构建Mac帧&#xff0c;发送ARP请求包&#xff0c;告诉所有在局域网的主机我的IP地址和Mac帧&#xff0c;与目的IP相同的主…

[lesson16]类的真正形态

类的真正形态 类的关键字 struct在C语言中以及有了自己的含义&#xff0c;必须继续兼容 在C中提供了新的关键字class用于类的定义 class和struct的用法是完全相同的 在用struct定义类时&#xff0c;所有成员的默认访问级别为public 在用class定义类时&#xff0c;所有成员…

Leetcode算法训练日记 | day22

一、二叉搜索树的最近公共祖先 1.题目 Leetcode&#xff1a;第 235 题 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足…

liunx环境变量学习总结

环境变量 在操作系统中&#xff0c;环境变量是一种特殊的变量&#xff0c;它们为运行的进程提供全局配置信息和系统环境设定。本文将介绍如何自定义、删除环境变量&#xff0c;特别是对重要环境变量PATH的管理和定制&#xff0c;以及与环境变量相关的函数使用。 自定义环境变…