前缀和算法详解


对于查询区间和的问题,可以预处理出来一个前缀和数组 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

注意点:
- 不用真正的创建一个前缀和数组去表示和,只需要用一个 sum 变量来计算即可
- 如果说整个前缀和都等于k的话,就代表 sum - k 等于 0,这个需要提前在哈希表中存储,因为此时需要在 0~-1 区间内去找一个和为0的次数,但是这个区间不存在,所以说需要提前设置为 1,当需要查找的时候,就是默认的 1
- 前缀和加入到哈希表的时机:需要在计算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;}
}

相关文章:
前缀和算法详解
对于查询区间和的问题,可以预处理出来一个前缀和数组 dp,数组中存储的是从下标 0 的位置到当前位置的区间和,这样只需要通过前缀和数组就可以快速的求出指定区间的和了,例如求 l ~ r 区间的和,就可以之间使用 dp[l - 1…...
Android-Handle消息传递和线程通信
本文为作者学习笔记,如有误,请各位大佬指点 目录 一、同步异步 二、Java多线程通信 三、Handler是什么 四、Handler相关的类 五、Handler常用方法 1. 发送消息 2. 接收处理消息 3. 切换线程 六、使用Handler 使用Handler更新UI 使用Handler延…...
【Kubernetes】常见面试题汇总(四十七)
目录 106.考虑一种情况,公司希望通过保持最低成本来提高效率和技术运营速度。您如何看待公司将如何实现这一目标? 107.假设一家公司想要修改其部署方法,并希望构建一个可扩展性和响应性更高的平台。您如何看待这家公司能够实现这一目标以满足…...
grafana全家桶-loki promtail收集k8s容器日志
loki是grafana旗下轻量级日志收集工具,为了减少loki对集群的影响,把loki的agent日志收集端promtail部署在k8s集群中,loki server部署在集群外面。这样简单做一个解耦,避免大量读写的应用影响到集群内业务服务。 一、promtail部署…...
HTML5+CSS+JavaScript剪子石头布游戏
HTML5CSSJavaScript剪子石头布游戏 用HTML5CSSJavaScript剪子石头布游戏实现剪子石头布游戏,游戏有成绩计数,人、机输赢情况,及平局情况。 ✂代表剪刀,▉代表石头,▓ 代表布,给出人机双方的出拳情况 游戏…...
Flask-3
文章目录 ORMFlask-SQLAlchemySQLAlchemy中的session对象数据库连接设置常用的SQLAlchemy字段类型常用的SQLAlchemy列约束选项 数据库基本操作模型类定义 数据表操作创建和删除表 数据操作基本查询SQLAlchemy常用的查询过滤器SQLAlchemy常用的查询结果方法多条件查询分页器聚合…...
Redis的基本使用
简介 传统的数据库是 关系数据库,但是Redis是键值对数据库传统的数据库是基于 磁盘存储的,但是Redis是基于 内存存储的 基于内存,读写性能更高内存是不大的,只能存储热点信息 安装 绿色软件,安装即可使用 安装服务 手…...
[241004] Linux 系统中配置文件的区别 | VirtualBox 7.1.2 发布,修复多项问题并提升性能
目录 Linux 系统中 /etc/profile, ~/.bash_profile, ~/.profile, ~/.bashrc 等配置文件的区别一、配置文件类型二、配置文件作用三、交互式登录 Shell 和非登录 Shell交互式登录 shell交互式非登录 shell 四、配置文件加载顺序五、~/.bash_profile 和 ~/.bashrc 的区别 Virtual…...
hbuilderx+uniapp+Android宠物用品商城领养服务系统的设计与实现 微信小程序沙箱支付
目录 项目介绍支持以下技术栈:具体实现截图HBuilderXuniappmysql数据库与主流编程语言java类核心代码部分展示登录的业务流程的顺序是:数据库设计性能分析操作可行性技术可行性系统安全性数据完整性软件测试详细视频演示源码获取方式 项目介绍 顾客 领养…...
SVN 迁移到 GIT,并保留提交记录
1)svn账号与git账号映射 创建 user.txt ,格式如下,user.txt 放置在git base here 所选目录下即可 schacon Scott Chacon <schacongeemail.com> selse Someo Nelse <selsegeemail.com> 为了获得 SVN 使用的作者名字列表…...
【数据结构与算法】LeetCode:堆和快排
文章目录 LeetCode:堆和快排排序数组数组中的第K个最大元素 (Hot 100)前 K 个高频元素(Hot 100)数据流的中位数(Hot 100) LeetCode:堆和快排 排序数组 排序数组 双向切分实现快排…...
文档大师:打造一站式 Word 报告解决方案
前言 在政府、医院、银行、财务以及销售等领域,常常需要创建各种报告文件来展开工作汇报,譬如季度销售报告、年度总结报告、体检报告和保险合同等。在没有报表工具支持之前,这类报告主要通过 Word 制作,费时费力且难以维护&#…...
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位版本 实际上只有两个取值,分别是4和6,4代表的是IPv4,6代表的是IPv6。 2.4位首部长度 IP协议报头的长度也是边长的,单位是*4,这里表示的大小为0~15,当数值为1…...
【分布式微服务云原生】掌握分布式缓存:Redis与Memcached的深入解析与实战指南
掌握分布式缓存:Redis与Memcached的深入解析与实战指南 摘要: 本文深入探讨了分布式缓存在现代分布式系统中的重要性,详细分析了Redis和Memcached两种主流的分布式缓存解决方案的原理和使用场景。文章不仅提供了核心技术的深入解析ÿ…...
计算机毕业设计 基于Python的智能文献管理系统的设计与实现 Python+Django+Vue 前后端分离 附源码 讲解 文档
🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…...
如何查看NVIDIA Container Toolkit是否配置成功
要确认 NVIDIA Container Toolkit 是否已成功配置,可以按照以下步骤进行检查: 1.检查 NVIDIA 驱动程序 首先,确保你的系统已经正确安装了 NVIDIA 驱动程序,并且可以识别你的 GPU。你可以使用 nvidia-smi 命令来进行检查…...
python全栈学习记录(二十一)类的继承、派生、组合
类的继承、派生、组合 文章目录 类的继承、派生、组合一、类的继承二、派生三、组合 一、类的继承 继承是一种新建类的方式,新建的类称为子类,被继承的类称为父类。 继承的特性是:子类会遗传父类的属性(继承是类与类之间的关系&a…...
Go语言实现长连接并发框架 - 任务执行流
文章目录 前言接口结构体接口实现项目地址最后 前言 你好,我是醉墨居士,上篇博客中我们实现了客户端的请求的实现,接下来我们要去实现对请求任务的处理,我们需要定义任务执行的流程 接口 trait/task.go type TaskFunc interfa…...
Flutter与原生代码通信
文章目录 1. 知识回顾2. 示例代码3. 经验总结我们在上一章回中介绍了通道相关的内容,本章回中将介绍其中的一种通道:MethodChannnel.闲话休提,让我们一起Talk Flutter吧。 1. 知识回顾 我们在上一章回中介绍了通道的概念和作用,并且提到了通道有不同的类型,本章回将其中一…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...

