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

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

💓博主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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DRF 常用功能

文章目录 一、主流认证方式Session认证Token认证JWT认证 二、DRF认证与权限Session认证所有视图&#xff08;全局&#xff09;启用认证视图级别启用认证 Token认证[推荐]安装APP启用Token认证生成数据库表(因为token要存储到数据库&#xff09;配置Token认证接口URL获取token使…

迭代器模式【行为模式C++】

1.简介 迭代器模式是一种行为设计模式&#xff0c; 让你能在不暴露集合&#xff08;聚合对象&#xff09;底层表现形式 &#xff08;列表、 栈和树等&#xff09; 的情况下遍历集合&#xff08;聚合对象&#xff09;中所有的元素。 迭代器的意义就是将这个行为抽离封装起来&a…

STM32F4 IAP跳转APP问题及STM32基于Ymodem协议IAP升级笔记

STM32F4 IAP 跳转 APP问题 ST官网IAP例程Chapter1 STM32F4 IAP 跳转 APP问题1. 概念2. 程序2.1 Bootloader 程序 问题现象2.2. APP程序 3. 代码4. 其他问题 Chapter2 STM32-IAP基本原理及应用 | ICP、IAP程序下载流程 | 程序执行流程 | 配置IAP到STM32F4xxxChapter3 STM32基于Y…

SQLite数据库在Linux系统上的使用

SQLite是一个轻量级的数据库解决方案&#xff0c;它是一个嵌入式的数据库管理系统。SQLite的特点是无需独立的服务器进程&#xff0c;可以直接嵌入到使用它的应用程序中。由于其配置简单、支持跨平台、服务器零管理&#xff0c;以及不需要复杂的设置和操作&#xff0c;SQLite非…

python如何输入多行

Python中的Input()函数在输入时&#xff0c;遇到回车符&#xff0c;那么一次输入就结束了。这不能满足输入多行文本并且行数也不确定的情形&#xff0c;当然输入空行也是允许的。 方法1&#xff1a;利用异常处理机制实现 lines[] while True:try:lines.append(input())except:…

达梦数据库清理归档日志的方法

达梦数据库清理归档日志的方法 在达梦数据库&#xff08;DM数据库&#xff09;中&#xff0c;归档日志文件是数据库运行过程中产生的&#xff0c;用于记录所有对数据库修改的详细信息。这些日志对于数据库的恢复非常关键&#xff0c;尤其是在进行灾难恢复或数据恢复时。然而&a…

关于Linux下的进程等待(进程篇)

目录 为什么存在进程等待&#xff1f;进程等待是在做什么&#xff1f; 怎样去执行进程等待&#xff1f; status options 为什么存在进程等待&#xff1f;进程等待是在做什么&#xff1f; 代码示例&#xff1a;模仿僵尸进程 #include <stdio.h> #include <unistd.…

xss跨站脚本攻击笔记

1 XSS跨站脚本攻击 1.1 xss跨站脚本攻击介绍 跨站脚本攻击英文全称为(Cross site Script)缩写为CSS&#xff0c;但是为了和层叠样式表(CascadingStyle Sheet)CSS区分开来&#xff0c;所以在安全领域跨站脚本攻击叫做XSS 1.2 xss跨战脚本攻击分类 第一种类型:反射型XSS 反射…

java数据结构与算法刷题-----LeetCode684. 冗余连接

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 并查集 并查集 解题思路&#xff1a;时间复杂度O( n ∗ l o g 2…

ThinkPHP审计(2) Thinkphp反序列化链5.1.X原理分析从0编写POC

ThinkPHP审计(2) Thinkphp反序列化链子5.1.X原理分析&从0编写POC 文章目录 ThinkPHP审计(2) Thinkphp反序列化链子5.1.X原理分析&从0编写POC动态调试环境配置Thinkphp反序列化链5.1.X原理分析一.实现任意文件删除二.实现任意命令执行真正的难点 Thinkphp反序列化链5.1.…

JVM规范中的运行时数据区

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a;每天一个知识点 ✨特色专栏&#xff1a…

SpringBoot 集成H2数据库,启动执行sql, 中文乱码

目录 H2数据库介绍 SpringBoot版本&#xff1a;SpringBoot 2.1.12.RELEASE 快速集成H2&#xff0c;maven依赖 快速集成H2&#xff0c;数据源及关键参数配置 spring.datasource.schema参数&#xff08;建表SQL脚本&#xff09; spring.datasource.data参数&#xff08;更新、…

Qt5 编译 Qt Creator 源码中的 linguist 模块

文章目录 下载 Qt Creator 源码手动翻译多语言自动翻译多语言 下载 Qt Creator 源码 Github: https://github.com/qt/qttools 笔记打算用 Qt 5.12.12 来编译 qt creator-linguist 所以笔者下载的是 tag - 5.12.12 &#xff0c;解压后如下&#xff0c;先删除多余的文件&#xf…

【Vue】Vue3中的OptionsAPI与CompositionAPI

文章目录 OptionsAPICompositionAPI对比总结 OptionsAPI 中文名:选项式API通过定义methods,computed,watch,data等属性方法&#xff0c;处理页面逻辑。以下是OptionsAPI代码结构 实例代码: <script lang"ts">// js或者tsimport { defineComponent } from vu…

【学习】软件测试需求分析要从哪些方面入手

软件测试需求分析是软件测试过程中非常重要的一个环节&#xff0c;它是为了明确软件测试的目标、范围、资源和时间等要素&#xff0c;以确保软件测试的有效性和全面性。本文将从以下几个方面对软件测试需求分析进行详细的阐述&#xff1a; 一、软件测试目标 软件测试目标是指…

读所罗门的密码笔记16_直通心智

1. 直通心智 1.1. 如今&#xff0c;科学家已经可以诱发触觉、压觉、痛觉和大约250种其他感觉 1.1.1. DARPA支持的触觉技术第一次让一位受伤的人能够用假肢和手指感知到被触碰的物体 1.1.2. 可以建立人工系统&#xff0c;来替换和弥补受损大脑的部分区域 1.1.3. 神经科学家能…

Nginx日志格式化和追踪

背景 Nginx是一款功能强大的Web服务器&#xff0c;对于网络环境中的日志记录和配置至关重要。定制化Nginx日志格式可以帮助管理员更好地监控服务器性能、分析用户行为并做出相应优化。在本文中&#xff0c;我们将深入探讨Nginx日志格式的高级定制化策略&#xff0c;包括理解基…

词频统计程序

使用Hadoop MapReduce处理文本文件&#xff0c;Mapper负责将文本分割为单词&#xff0c;然后Reducer对每个单词进行计数&#xff0c;最后将结果写入输出文件。 // 定义WordCount公共类 public class WordCount {// 主入口方法&#xff0c;处理命令行参数public static void m…

循环神经网络RNN

循环神经网络RNN是一种人工神经网络&#xff0c;旨在处理时间序列、语音和自然语言等序列数据。将RNN 想象成传送带&#xff0c;一次处理一个元素的信息&#xff0c;从而 "记住 "前一个元素的信息&#xff0c;对下一个元素做出预测。   想象一下&#xff0c;我们有…

【多线程】Thread的常见属性 | 终止线程 | 等待线程 | 休眠线程 | 线程安全

文章目录 一、Thread的方法Thread的常见属性后台线程&#xff08;守护线程&#xff09;设置后台线程是否存活 启动线程终止\打断一个线程1.创建标志位2.调用 interrupt() 方法 等待一个线程 join()t.join&#xff08;&#xff09;的工作过程&#xff1a; 休眠一个进程sleep 二、…