当前位置: 首页 > news >正文

前缀和算法详解

在这里插入图片描述

对于查询区间和的问题,可以预处理出来一个前缀和数组 dp,数组中存储的是从下标 0 的位置到当前位置的区间和,这样只需要通过前缀和数组就可以快速的求出指定区间的和了,例如求 l ~ r 区间的和,就可以之间使用 dp[l - 1] - dp[r] 来计算

1. DP34 【模板】前缀和

DP34 【模板】前缀和

这里从下标 1 开始填是为了在初始化前缀和数组时更方便

public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int N = sc.nextInt();int p = sc.nextInt();int[] arr = new int[N + 1];long[] dp = new long[N + 1];for (int i = 1; i <= N; i++) {arr[i] = sc.nextInt();}for (int i = 1; i <= N; i++) {dp[i] = dp[i - 1] + arr[i];}int l = 0, r = 0;while (p-- != 0) {l = sc.nextInt();r = sc.nextInt();System.out.println(dp[r] - dp[l - 1]);}}
}

2. DP35 【模板】二维前缀和

二维前缀和模版

和一维的前缀和数组类似,这里需要先预处理出来一个前缀和矩阵 dp[][],dp[i][j] 就表示从(1,1)到(i,j)这个矩阵中的所有元素的和

放到矩阵中可以看出,如果想要求(1,1)到(i,j)区间内的区域和,需要先加上 A,B,C,D 四个区域的和,如果单独的表示 B 区域或者 C 并不好表示,但是 A + B 和 A + C 是很好表示的,把这两个区域加起来再减去多加的 A ,再加上 D 就是整个区域的和

得到了前缀和数组之后,该怎么去使用呢?

如果说给出了(x1,y1)(x2,y2)两个点,那么就是求红色框的元素的和

也就是求出 D 区域的和,由于 B 和 C 并不好单独转换,就可以转化为 A+B+C+D 的值先减去 A+B 的值,再减去 A + C 的值,此时方法 A 被多减了一次,再加上就是 D 区域的和了

public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt(), m = sc.nextInt();int q = sc.nextInt();int[][] A = new int[n + 1][m + 1];long[][] dp = new long[n + 1][m + 1];for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {A[i][j] = sc.nextInt();}}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {dp[i][j] = dp[i][j - 1] + dp[i - 1][j] - dp[i - 1][j - 1]+ A[i][j];}}int x1 = 0,y1 = 0,x2 = 0,y2 = 0;while (q-- != 0) {x1 = sc.nextInt();y1 = sc.nextInt();x2 = sc.nextInt();y2 = sc.nextInt();System.out.println(dp[x2][y2] - dp[x2][y1 - 1] - dp[x1 - 1][y2] + dp[x1 - 1][y1 - 1]);}}
}

3. 寻找数组的中心下标

724. 寻找数组的中心下标

根据题目要求就是求 0~ i - 1区间的和是否和区间 i + 1~n - 1 的和相等,那么此题dp[i] 就表示的是[0,i-1] 区间的和而不是之前的 0 ~ i 区间的和了,相应的,状态转移方程也要有所变化

同时这道题还需要求一个后缀和数组用来描述后半段的区间和,也是同样的道理,只不过 dp[i] 表示的是[i + 1,n - 1] 区间的和,这段区间的状态转移方程也就是 dp[i+1] + nums[i + 1]

class Solution {public int pivotIndex(int[] nums) {int n = nums.length;int[] dp = new int[n];int[] g = new int[n];for (int i = 1; i < n; i++) {dp[i] = dp[i - 1] + nums[i - 1];}for (int i = n - 2; i >= 0; i--) {g[i] = g[i + 1] + nums[i + 1];}for (int i = 0; i < n; i++) {if (g[i] == dp[i]) {return i;}}return -1;}
}

4. 除自身以外数组的乘积

238. 除自身以外数组的乘积

这道题其实就和上道题非常类似,把 i 位置之前的数都求一个前缀积,之后的数求一个后缀积,只需要把前缀积和后缀积相乘就可以了

class Solution {public int[] productExceptSelf(int[] nums) {int n = nums.length;int[] f = new int[n];int[] g = new int[n];int[] ans = new int[n];f[0] = 1;g[n - 1] = 1;for (int i = 1; i < n; i++) {f[i] = f[i - 1] * nums[i - 1];}for (int i = n - 2; i >= 0; i--) {g[i] = g[i + 1] * nums[i + 1];}for (int i = 0; i < n; i++) {ans[i] = f[i] * g[i];}return ans;}
}

5. 和为 K 的子数组

560. 和为 K 的子数组

思路:每次都求0 ~ i - 1 区间内有多少个子数组是和为 k 的,如果正常求的话,时间复杂度就是O(n^2)了,所以说可以把子数组和为k的个数存在哈希表中去求,也就需要在求和的过程中就把这些数据添加到哈希表中,而求0 ~ i - 1 区间,和为 k 的子数组,就可以转化为求前半部分的哪段区间的和为整段区间和 sum - k

注意点:

  1. 不用真正的创建一个前缀和数组去表示和,只需要用一个 sum 变量来计算即可
  2. 如果说整个前缀和都等于k的话,就代表 sum - k 等于 0,这个需要提前在哈希表中存储,因为此时需要在 0~-1 区间内去找一个和为0的次数,但是这个区间不存在,所以说需要提前设置为 1,当需要查找的时候,就是默认的 1
  3. 前缀和加入到哈希表的时机:需要在计算i位置之前,保存0~i-1区间的前缀和,也就是知道 sum - k的次数,i-1统计之后才可以把i位置的前缀和存入哈希表中
class Solution {public int subarraySum(int[] nums, int k) {int sum = 0,ret = 0;HashMap<Integer,Integer> hash = new HashMap<>();hash.put(0,1);for(int x : nums){sum+=x;//以当前元素为结尾时有多少符合条件的答案ret+=hash.getOrDefault(sum - k,0);hash.put(sum,hash.getOrDefault(sum,0) + 1);}return ret;}
}

6. 和可被 K 整除的子数组

974. 和可被 K 整除的子数组

同余定理:(a - b) / p = k......0 => a % p = b % p

就是如果 a - b 的差能够被 p 整除的话,那么 a 和 b 对 p 取模就相等

在 Java 中,一个负数对一个正数取模的话得到的是一个负数,如果想要修正为正数的话可以使用下面的式子

首先把负数的余数变为正数,但如果原来就是正数的话还是不对的,所以需要再取一个余数

这样就可以把题目转化为只需要求在 i 之前有多少个区间对 K 取模之后等于 0 ,也就和上一题类似了

class Solution {public int subarraysDivByK(int[] nums, int k) {int sum = 0, ret = 0;HashMap<Integer, Integer> hashMap = new HashMap<>();hashMap.put(0 % k, 1);for (int x : nums) {sum += x;int r = (sum % k + k)% k;ret += hashMap.getOrDefault( r, 0);hashMap.put(r, hashMap.getOrDefault(r, 0) + 1);}return ret;}
}

7. 连续数组

525. 连续数组

如果直接统计 0 和 1 的个数的话还是比较麻烦的,可以转化一下,把所有的 0 都变成 - 1,当 0 和 1 的个数相等时,也就是区间和等于 0 的情况,也就转化为了之前的求和为 k 的子数组的问题,只不过之前求的是个数,这题求的是长度,

class Solution {public int findMaxLength(int[] nums) {HashMap<Integer, Integer> hash = new HashMap<>();hash.put(0, -1);int sum = 0, ret = 0;for (int i = 0; i < nums.length; i++) {sum += (nums[i] == 0 ? -1 : 1);if (hash.containsKey(sum)) {ret = Math.max(ret, i - hash.get(sum));} else {hash.put(sum, i);}}return ret;}
}

需要注意的是,如果说在之后发现有重复的 sum 的时候,就不需要再存放进哈希表中了,因为此时的长度肯定是没有第一次的长的,就会影响后面使用 i - j 时计算的长度

8. 矩阵区域和

1314. 矩阵区域和

也就是周围所有元素的和

首先就是先预处理一个二维前缀和数组,然后再求( i , j ) 位置的值

求(i , j )位置的值的时候和之前讲的前缀和模版类似

然后就是怎么求坐标的问题,知道(i , j)坐标之后,求此处的值的话就需要求左上角和右下角的坐标,然后才能求出这个区域中的元素和

关于下标的映射关系,由于题目中的数组是从下标 0 计算的,为了方便是将 dp 表从下标为 1 开始计算的,所以说后续再继续从 dp 表中使用值的时候是需要把 x ,y 坐标都加上 1 的

class Solution {public int[][] matrixBlockSum(int[][] mat, int k) {int m = mat.length, n = mat[0].length;int[][] dp = new int[m + 1][n + 1];int[][] ans = new int[m][n];for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {dp[i][j] = dp[i - 1][j] + dp[i][j-1] - dp[i - 1][j - 1] + mat[i - 1][j - 1];}}for(int i = 0; i< m;i++){for(int j = 0;j < n;j++){int x1 = Math.max(0,i - k) + 1,y1 = Math.max(0,j - k) + 1;int x2 = Math.min(m - 1,i + k) + 1,y2 = Math.min(n - 1, j + k) + 1;ans[i][j] = dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1];}}return ans;}
}

在这里插入图片描述

相关文章:

前缀和算法详解

对于查询区间和的问题&#xff0c;可以预处理出来一个前缀和数组 dp&#xff0c;数组中存储的是从下标 0 的位置到当前位置的区间和&#xff0c;这样只需要通过前缀和数组就可以快速的求出指定区间的和了&#xff0c;例如求 l ~ r 区间的和&#xff0c;就可以之间使用 dp[l - 1…...

Android-Handle消息传递和线程通信

本文为作者学习笔记&#xff0c;如有误&#xff0c;请各位大佬指点 目录 一、同步异步 二、Java多线程通信 三、Handler是什么 四、Handler相关的类 五、Handler常用方法 1. 发送消息 2. 接收处理消息 3. 切换线程 六、使用Handler 使用Handler更新UI 使用Handler延…...

【Kubernetes】常见面试题汇总(四十七)

目录 106.考虑一种情况&#xff0c;公司希望通过保持最低成本来提高效率和技术运营速度。您如何看待公司将如何实现这一目标&#xff1f; 107.假设一家公司想要修改其部署方法&#xff0c;并希望构建一个可扩展性和响应性更高的平台。您如何看待这家公司能够实现这一目标以满足…...

grafana全家桶-loki promtail收集k8s容器日志

loki是grafana旗下轻量级日志收集工具&#xff0c;为了减少loki对集群的影响&#xff0c;把loki的agent日志收集端promtail部署在k8s集群中&#xff0c;loki server部署在集群外面。这样简单做一个解耦&#xff0c;避免大量读写的应用影响到集群内业务服务。 一、promtail部署…...

HTML5+CSS+JavaScript剪子石头布游戏

HTML5CSSJavaScript剪子石头布游戏 用HTML5CSSJavaScript剪子石头布游戏实现剪子石头布游戏&#xff0c;游戏有成绩计数&#xff0c;人、机输赢情况&#xff0c;及平局情况。 ✂代表剪刀&#xff0c;▉代表石头&#xff0c;▓ 代表布&#xff0c;给出人机双方的出拳情况 游戏…...

Flask-3

文章目录 ORMFlask-SQLAlchemySQLAlchemy中的session对象数据库连接设置常用的SQLAlchemy字段类型常用的SQLAlchemy列约束选项 数据库基本操作模型类定义 数据表操作创建和删除表 数据操作基本查询SQLAlchemy常用的查询过滤器SQLAlchemy常用的查询结果方法多条件查询分页器聚合…...

Redis的基本使用

简介 传统的数据库是 关系数据库&#xff0c;但是Redis是键值对数据库传统的数据库是基于 磁盘存储的&#xff0c;但是Redis是基于 内存存储的 基于内存&#xff0c;读写性能更高内存是不大的&#xff0c;只能存储热点信息 安装 绿色软件&#xff0c;安装即可使用 安装服务 手…...

[241004] Linux 系统中配置文件的区别 | VirtualBox 7.1.2 发布,修复多项问题并提升性能

目录 Linux 系统中 /etc/profile, ~/.bash_profile, ~/.profile, ~/.bashrc 等配置文件的区别一、配置文件类型二、配置文件作用三、交互式登录 Shell 和非登录 Shell交互式登录 shell交互式非登录 shell 四、配置文件加载顺序五、~/.bash_profile 和 ~/.bashrc 的区别 Virtual…...

hbuilderx+uniapp+Android宠物用品商城领养服务系统的设计与实现 微信小程序沙箱支付

目录 项目介绍支持以下技术栈&#xff1a;具体实现截图HBuilderXuniappmysql数据库与主流编程语言java类核心代码部分展示登录的业务流程的顺序是&#xff1a;数据库设计性能分析操作可行性技术可行性系统安全性数据完整性软件测试详细视频演示源码获取方式 项目介绍 顾客 领养…...

SVN 迁移到 GIT,并保留提交记录

1&#xff09;svn账号与git账号映射 创建 user.txt &#xff0c;格式如下&#xff0c;user.txt 放置在git base here 所选目录下即可 schacon Scott Chacon <schacongeemail.com> selse Someo Nelse <selsegeemail.com> 为了获得 SVN 使用的作者名字列表&#xf…...

【数据结构与算法】LeetCode:堆和快排

文章目录 LeetCode&#xff1a;堆和快排排序数组数组中的第K个最大元素 &#xff08;Hot 100&#xff09;前 K 个高频元素&#xff08;Hot 100&#xff09;数据流的中位数&#xff08;Hot 100&#xff09; LeetCode&#xff1a;堆和快排 排序数组 排序数组 双向切分实现快排…...

文档大师:打造一站式 Word 报告解决方案

前言 在政府、医院、银行、财务以及销售等领域&#xff0c;常常需要创建各种报告文件来展开工作汇报&#xff0c;譬如季度销售报告、年度总结报告、体检报告和保险合同等。在没有报表工具支持之前&#xff0c;这类报告主要通过 Word 制作&#xff0c;费时费力且难以维护&#…...

Python 数字专题:全方位解析整数

目录 1. 引言 2. 整数的基本概念 2.1 定义 2.2 整数的表示 2.3 创建整数 3. 整数的基本操作 3.1 算术运算 3.2 比较运算 3.3 位运算 4. 内置函数与方法 4.1 int() 函数 4.2 abs() 函数 4.3 pow() 函数 5. 整数的性能优化 5.1 大整数的处理 5.2 使用 numpy 6. 应…...

IP协议报文

一.IP协议报头结构 二.IP协议报头拆解 1.4位版本 实际上只有两个取值&#xff0c;分别是4和6&#xff0c;4代表的是IPv4&#xff0c;6代表的是IPv6。 2.4位首部长度 IP协议报头的长度也是边长的&#xff0c;单位是*4&#xff0c;这里表示的大小为0~15&#xff0c;当数值为1…...

【分布式微服务云原生】掌握分布式缓存:Redis与Memcached的深入解析与实战指南

掌握分布式缓存&#xff1a;Redis与Memcached的深入解析与实战指南 摘要&#xff1a; 本文深入探讨了分布式缓存在现代分布式系统中的重要性&#xff0c;详细分析了Redis和Memcached两种主流的分布式缓存解决方案的原理和使用场景。文章不仅提供了核心技术的深入解析&#xff…...

计算机毕业设计 基于Python的智能文献管理系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…...

如何查看NVIDIA Container Toolkit是否配置成功

要确认 NVIDIA Container Toolkit 是否已成功配置&#xff0c;可以按照以下步骤进行检查&#xff1a; 1.检查 NVIDIA 驱动程序 首先&#xff0c;确保你的系统已经正确安装了 NVIDIA 驱动程序&#xff0c;并且可以识别你的 GPU。你可以使用 nvidia-smi 命令来进行检查&#xf…...

python全栈学习记录(二十一)类的继承、派生、组合

类的继承、派生、组合 文章目录 类的继承、派生、组合一、类的继承二、派生三、组合 一、类的继承 继承是一种新建类的方式&#xff0c;新建的类称为子类&#xff0c;被继承的类称为父类。 继承的特性是&#xff1a;子类会遗传父类的属性&#xff08;继承是类与类之间的关系&a…...

Go语言实现长连接并发框架 - 任务执行流

文章目录 前言接口结构体接口实现项目地址最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;上篇博客中我们实现了客户端的请求的实现&#xff0c;接下来我们要去实现对请求任务的处理&#xff0c;我们需要定义任务执行的流程 接口 trait/task.go type TaskFunc interfa…...

Flutter与原生代码通信

文章目录 1. 知识回顾2. 示例代码3. 经验总结我们在上一章回中介绍了通道相关的内容,本章回中将介绍其中的一种通道:MethodChannnel.闲话休提,让我们一起Talk Flutter吧。 1. 知识回顾 我们在上一章回中介绍了通道的概念和作用,并且提到了通道有不同的类型,本章回将其中一…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...