前缀和算法详解

在这里插入图片描述

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

在这里插入图片描述

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

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

相关文章

河南做网站与SEO:如何提升搜索引擎排名

河南做网站与SEO&#xff1a;如何提升搜索引擎排名 在当今数字化时代&#xff0c;越来越多的企业意识到互联网的重要性&#xff0c;特别是在河南这样一个快速发展的地区&#xff0c;建立一个优秀的网站已经成为企业发展的必要条件。而在建立网站的同时&#xff0c;SEO&#xff…

Spring Gateway学习

系列文章目录 JavaSE基础知识、数据类型学习万年历项目代码逻辑训练习题代码逻辑训练习题方法、数组学习图书管理系统项目面向对象编程&#xff1a;封装、继承、多态学习封装继承多态习题常用类、包装类、异常处理机制学习集合学习IO流、多线程学习仓库管理系统JavaSE项目员工…

高性能防静电主轴4033 AC-ESD 在线路板切割中的非凡表现

随着电子产品的日益小型化/集成化&#xff0c;线路板的制造也面临着更高的挑战。线路板分板作为电子制造流程中的关键环节&#xff0c;其效率和精度直接影响到最终产品的质量和市场竞争力。因此专用的高性能防静电主轴SycoTec 4033 AC-ESD凭借其卓越的性能&#xff0c;成为众多…

笔记本电脑怎么多选删除文件?误删除文件怎么办

在日常使用笔记本电脑中&#xff0c;我们可能会遇到需要删除大量文件的情况&#xff0c;例如清理临时文件、整理文档或卸载不再需要的程序。手动一个一个地删除不仅效率低下&#xff0c;还可能遗漏某些文件。那么&#xff0c;如何在笔记本电脑上高效地进行多选删除操作呢&#…

15分钟学 Python 第33天 :函数式编程简介

Day 33: 函数式编程简介 1. 引言 函数式编程是一种程序设计范式&#xff0c;它将计算视为数学函数的求值&#xff0c;避免了程序中的可变状态和副作用。Python虽然是一种多范式语言&#xff08;支持命令式、面向对象和函数式编程&#xff09;&#xff0c;但其函数式编程的特性…

WPF之UI进阶--控件样式与样式模板及词典

WPF的优势之一就是能够更加容易快捷的对窗体和控件的外面进行改造&#xff0c;换句话说&#xff0c;那就是UI设计个性化更加容易。主要是借助了样式、模板及词典来实现的。那么本篇博文就一一对他们进行介绍。 文章目录 一、样式1: 定义样式2: 使用Setter设置属性关于Property和…

CSS3--美开二度

免责声明&#xff1a;本文仅做分享&#xff01; 目录 定位 相对定位 绝对定位 定位居中 固定定位 堆叠层级 z-index 定位-小结 CSS 精灵 京东案例 字体图标 下载字体 使用字体 上传矢量图 CSS 修饰属性 垂直对齐方式 vertical-align 过渡 transition 透明度 opa…

二、kafka生产与消费全流程

一、使用java代码生产、消费消息 1、生产者 package com.allwe.client.simple;import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.clients.pr…

C# 游戏引擎中的协程

前言 书接上回&#xff0c;我谈到了Unity中的协程的重要性&#xff0c;虽然协程不是游戏开发“必要的”&#xff0c;但是它可以在很多地方发挥优势。 为了在Godot找回熟悉的Unity协程开发手感&#xff0c;不得不自己做一个协程系统&#xff0c;幸运的是&#xff0c;有了Unity的…

TI DSP TMS320F280025 Note15:串口SCI的使用

TMS320F280025 串口SCI的使用 ` 文章目录 TMS320F280025 串口SCI的使用框图分析串口特点可编程数据格式SCI端口中断非FIFO/FIFO模式下SCI中断的操作/配置UartDriver.cUartDriver.h串口时钟由PCLKCR7控制使能,默认位系统时钟4分频 串口接收与发送都可以触发中断 串口使用的引脚…

JAVA并发编程高级——JDK 新增的原子操作类 LongAdder

LongAdder 简单介绍 前面讲过,AtomicLong通过CAS提供了非阻塞的原子性操作,相比使用阻塞算法的同步器来说它的性能已经很好了,但是JDK开发组并不满足于此。使用AtomicLong 时,在高并发下大量线程会同时去竞争更新同一个原子变量,但是由于同时只有一个线程的CAS操作会成功,…

【C语言】指针篇 | 万字笔记

写在前面 在学习C语言过程&#xff0c;总有一个要点难点离不开&#xff0c;那就是大名鼎鼎的C语言指针&#xff0c;也是应为有指针的存在&#xff0c;使得C语言一直长盛不衰。因此不才把指针所学的所有功力都转换成这个笔记。希望对您有帮助&#x1f970;&#x1f970; 学习指…

基于Springboot+Vue的饮食营养管理信息系统(含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统中…

Hystrix学习

系列文章目录 JavaSE基础知识、数据类型学习万年历项目代码逻辑训练习题代码逻辑训练习题方法、数组学习图书管理系统项目面向对象编程&#xff1a;封装、继承、多态学习封装继承多态习题常用类、包装类、异常处理机制学习集合学习IO流、多线程学习仓库管理系统JavaSE项目员工…

MAC M1 安装brew 配置环境变量,安装dart

一. 下载 brew 1. 终端输入 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 2. 如遇到下载失败情况&#xff0c;需要VPN/代理 curl: (7) Failed to connect to raw.githubusercontent.com port 443 after 8 m…

MongoDB简介

1、说到MongoDB就必须说下什么是NoSQL? NoSQL(NoSQL Not Only SQL)&#xff0c;意即反SQL运动&#xff0c;指的是非关系型的数据库&#xff0c;是一项全新的数据库革命性运动&#xff0c;早期就有人提出&#xff0c;发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系…

Java | Leetcode Java题解之第454题四数相加II

题目&#xff1a; 题解&#xff1a; class Solution {public int fourSumCount(int[] A, int[] B, int[] C, int[] D) {Map<Integer, Integer> countAB new HashMap<Integer, Integer>();for (int u : A) {for (int v : B) {countAB.put(u v, countAB.getOrDefa…

被字节恶心到了

字节 日常逛 xhs 看到一篇吐槽贴&#xff0c;表示被公司恶心到了&#xff1a; 这位网友表示&#xff0c;最近是公司举办了 Q2 和 H1 的优秀员工表彰&#xff0c;自己的 1&#xff08;直属领导&#xff09;评上了&#xff0c;但仔细一看&#xff0c;1 获奖的所有产出都是自己的&…

实时数字人DH_live使用案例

参看: https://github.com/kleinlee/DH_live ubuntu 测试 apt install ffmpeg 下载安装: git clone https://github.com/kleinlee/DH_live.git cd DH_liveconda create -n dh_live python=3.12 conda activate dh_live pip install -r requirements.txt pip install torch …

突发:Sam万字长文,OpenAI o1超越人类,o1模型训练原理、微调、能力来源-AI已死,大模型当立

OpenAl o1大模型&#xff1a;原理、突破、前景及影响 北京时间2024年9月13日凌晨&#xff0c;OpenAI正式发布了新的人工智能模型o1&#xff08;o是orion猎户座&#xff0c;1代表从头再来&#xff0c;也意味着后续将出现更多序列&#xff09;&#xff0c;就是此前OpenAI一直在高…