前缀和算法详解

news2024/11/25 11:01:28

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java继承、final/protected说明、super/this辨析

目录 1.什么是继承 2.继承的特征 3.子类构造方法 4.super和this辨析 5.再谈初始化 6.protected关键字用法说明 7.final的用法说明 1.什么是继承 上面的这个animal就是基类&#xff0c;我们的这个dog和bird都是继承这个基类的特征&#xff0c;使用的是extends这个关键字&a…

【重学 MySQL】五十六、位类型

【重学 MySQL】五十六、位类型 定义赋值与使用注意事项应用场景 在MySQL数据库中&#xff0c;位类型&#xff08;BIT类型&#xff09;是一种用于存储位字段值的数据类型。 定义 BIT(n)表示n个位字段值&#xff0c;其中n是一个范围从1到64的整数。这意味着你可以存储从1位到64…

终于知道神秘的蓝莓真身了

黑森林实验室&#xff08;Black Forest Labs&#xff0c;简称 BFL&#xff09;是一家初创公司&#xff0c;由流行的 Stable Diffusion AI 图像生成模型的创建者创立&#xff0c;该模型是许多 AI 图像生成应用程序和服务&#xff08;如 Midjourney&#xff09;的基础。 这意味着…

github/git密钥配置与使用

零、前言 因为要在ubuntu上做点东西&#xff0c;发现git clone 的时候必须输账户密码&#xff0c;后来发现密码是token&#xff0c;但是token一大串太烦了&#xff0c;忙了一天发现可以通过配置 公钥 来 替代 http 的 部署方式。 一、生成 ssh 密钥对 我们先测试下能不能 连接…

Linux 信号详解

目录 一.前置知识 1.前台进程和后台进程 a.概念理解 b.相关指令 2.信号的前置知识 a.Linux 系统下信号的概念 b.进程对信号的处理方式 3.信号的底层机制 二.详解信号 1.信号的产生 a.键盘组合键 b.kill 指令和系统调用接口 ① kill 指令 ② kill() 系统调用接口 ③ raise() 系统…

Stable Diffusion绘画 | 来训练属于自己的模型:打标处理与优化

上一篇完成的打标工作&#xff0c;是为了获取提示词&#xff0c;让AI认识和学习图片的特征。 因此&#xff0c;合适、恰当、无误的提示词&#xff0c;对最终模型效果是相当重要的。 Tag 如何优化 通过软件自动生成的 Tag 只是起到快速建立大体架构的作用&#xff0c;里面会涉…

2023年全国大学生数学建模竞赛C题——针对蔬菜类商品定价与补货决策的研究

摘要 本文针对生鲜超市中蔬菜类商品的补货和定价策略问题&#xff0c;建立时间序列预测模型&#xff0c;以及目标规划分析&#xff0c;从而让生鲜超市的收益达到最大。 针对问题一&#xff0c;首先对数据进行处理&#xff0c;对销售量异常值进行剔除、对缺失值补0 处理…

SOMEIP_ETS_150: SD_Send_triggerEventUINT8Multicast_Eventgroup_6

测试目的&#xff1a; 验证DUT在Tester订阅事件组后&#xff0c;能够响应Tester触发的triggerEventUINT8Multicast方法&#xff0c;并将TestEventUINT8Multicast事件发送到订阅请求中端点选项指定的IP地址和端口。 描述 本测试用例旨在确保DUT能够正确处理事件组的订阅请求&…

【nlp自然语言】知识图谱,全文检索,自然语言nlp,数据资产标签,集成管理平台

一、项目介绍 一款全源码&#xff0c;可二开&#xff0c;可基于云部署、私有部署的企业级知识库云平台&#xff0c;一款让企业知识变为实打实的数字财富的系统&#xff0c;应用在需要进行文档整理、分类、归集、检索、分析的场景。 为什么建立知识库平台&#xff1f; 助力企业…

基于SpringBoot+Vue+MySQL的旅游网站

系统展示 用户前台界面 管理员后台界面 系统背景 随着社会的不断发展和人们生活水平的提高&#xff0c;旅游活动逐渐成为人们生活中不可或缺的一部分。传统的旅游服务方式存在信息不对称、服务流程繁琐等问题。为了改善用户体验、提高服务效率&#xff0c;采用现代化的技术手段…

为什么说网站的可读性是引流量的重要环节

网站的可读性是指网站内容易于阅读和理解的程度。网站的可读性是引流量的重要环节&#xff0c;因为它直接影响到用户对网站内容的理解和吸收&#xff0c;进而影响用户的停留时间和转化率。以下是详细分析&#xff1a; 提升用户体验&#xff1a;网站的可读性好意味着用户可以更…

[uni-app]小兔鲜-06地址+sku+购物车

收址模块 准备 地址管理分包页面 和 添加地址分包页面 新增和修改地址 import type { AddressParams, AddressItem } from /types/address import { http } from /utils/http/*** 添加收货地址* param data 请求参数*/ export const postMemberAddressAPI (data: AddressPara…

Stable Diffusion绘画 | 插件-Deforum:动态视频生成(上篇)

Deforum 与 AnimateDiff 不太一样&#xff0c; AnimateDiff 是生成丝滑变化视频的&#xff0c;而 Deforum 的丝滑程度远远没有 AnimateDiff 好。 它是根据对比前面一帧的画面&#xff0c;然后不断生成新的相似图片&#xff0c;来组合成一个完整的视频。 Deforum 的优点在于可…

多模态系统中专家混合(MoE)复杂性的解读

引言 在迅速发展的人工智能领域&#xff0c;整合多种数据模态&#xff08;如文本、图像、音频和传感器数据&#xff09;是一个极具挑战性的任务。传统的单一模型AI系统通常难以应对同时处理多模态时产生的指数级复杂性。而这正是混合专家&#xff08;Mixture of Experts&#…

如何正确拆分数据集?常见方法最全汇总

将数据集划分为训练集&#xff08;Training&#xff09;和测试集&#xff08;Testing&#xff09;是机器学习和统计建模中的重要步骤&#xff1a; 训练集&#xff08;Training&#xff09;&#xff1a;一般来说 Train 训练集会进一步再分为 Train 训练集与 Validation 验证集两…

ElasticSearch备考 -- Update by query

一、题目 有个索引task&#xff0c;里面的文档长这样 现在需要添加一个字段all&#xff0c;这个字段的值是以下 a、b、c、d字段的值连在一起 二、思考 需要把四个字段拼接到一起&#xff0c;组成一个新的字段&#xff0c;这个就需要脚本&#xff0c; 这里有两种方案&#xff…

geodatatool(地图资源下载工具)3.8更新

geodatatool&#xff08;地图资源下载工具&#xff09;3.8&#xff08;新&#xff09;修复更新&#xff0c;修复更新包括&#xff1a; 1.高德POI数据按行政区划下载功能完善。 2.修正高德POI数据类型重复问题。 3.对高德KEY数据访问量超过最大限制时&#xff0c;提示错误并终止…

RK3568平台(显示篇)车机图像显示偏白问题分析

一.显示偏白图片对比 正常图像: 偏白图像: 二.分析过程

手把手教你使用Tensorflow2.7完成人脸识别系统,web人脸识别(Flask框架)+pyqt界面,保姆级教程

目录 前言一、系统总流程设计二、环境安装1. 创建虚拟环境2.安装其他库 三、模型搭建1.采集数据集2. 数据预处理3.构建模型和训练 五、摄像头测试六、web界面搭建与pyqt界面搭建报错了并解决的方法总结 前言 随着人工智能的不断发展&#xff0c;机器学习和深度学习这门技术也越…

YOLO11改进|注意力机制篇|引入注意力与卷积混合的ACmix

目录 一、ACmix注意力机制1.1ACmix注意力介绍1.2ACmix核心代码 二、添加ACmix注意力机制2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、ACmix注意力机制 1.1ACmix注意力介绍 ACmix设计为一个结合了卷积和自注意力机制优势的混合模块&am…