Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >前缀和算法详解

前缀和算法详解

作者头像
2的n次方
发布于 2024-10-15 08:03:26
发布于 2024-10-15 08:03:26
13700
代码可运行
举报
文章被收录于专栏:CSDN 迁移文章CSDN 迁移文章
运行总次数:0
代码可运行

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

1. DP34 【模板】前缀和

DP34 【模板】前缀和

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 区域的和了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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]

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 位置之前的数都求一个前缀积,之后的数求一个后缀积,只需要把前缀积和后缀积相乘就可以了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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位置的前缀和存入哈希表中
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 ,也就和上一题类似了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 的子数组的问题,只不过之前求的是个数,这题求的是长度,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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;
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-10-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Webpack】320- Webpack4 入门手册(共 18 章)(下)
最近和部门老大,一起在研究团队【EFT - 前端新手村】的建设,目的在于:帮助新人快速了解和融入公司团队,帮助零基础新人学习和入门前端开发并且达到公司业务开发水平。
pingan8787
2019/08/20
2.4K0
【Webpack】320- Webpack4 入门手册(共 18 章)(下)
webpack从零搭建开发环境
为了方便也可以这么写,使用 npm run 命令这个命令执行的时候默认会把 node_modules 的.bin 文件放到全局上,执行之后销毁npm run buildnpm run dev
小丑同学
2020/09/21
1.4K0
webpack 基础知识整理
webpack是一个 模块打包工具,支持所有的打包语法,比如 ES Module、CommonJS、CMD、AMD。初期的webpack是用来模块打包js的,发展到现在,已经可以打包很多种文件类型,比如 css、img 。
神葳
2021/01/22
1.5K0
Vue学习-Webpack
从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具。
花猪
2022/02/17
1.4K0
Vue学习-Webpack
前端工程化 - webpack 基础
默认配置文件 webpack.config.js,可以通过 webpack --config 指定配置文件
Cellinlab
2023/05/17
3440
Webpack基本使用
Webpack介绍:主要用于web项目中打包资源进行自动构建,Webpack将所有资源视为JS的模块来进行构建,所以对于CSS,Image等非JS类型的文件,Webpack会使用相应的加载(loader)器来加载成其可识别的JS模块资源,通过配置一些信息,就能将资源进行打包构建,更好地实现前端的工程化 Webpack安装 本地安装: npm install -D webpack -D 实际上是简写 --dev-save 如果你使用Webpack 4+ 版本, 你还需要安装CLI. npm ins
一个淡定的打工菜鸟
2018/09/06
4990
Webpack基本使用
Webpack系列——快速入门
多文件入口 对entry采用对象写法,指定对应的键值对,为了输出这多个文件可以使用占位符
用户1515472
2019/07/24
7090
webpack@3简单使用
这篇博客用的是webpack3的版本,作为入门理解学习 非原创,只为学习记录。博客大部分内容引用来源如下:
代码之风
2018/10/31
1.1K0
【谷粒学院】013-Webpack
Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源; 从图中我们可以看出,Webpack 可以将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求;
訾博ZiBo
2025/01/06
1360
【谷粒学院】013-Webpack
2022-webpack5实战教程
打包成功之后,查看dist目录下的index.html文件是否引用了打包之后的js
gogo2027
2022/10/17
1K0
4-12 环境变量的使用
其实我么之前已经将webpack.config.js 按环境进行去了区分配置,那么在公共配置文件中我们能否知道当前所处的环境,并据此做逻辑区分呢?
love丁酥酥
2020/03/26
5820
初探webpack之编写plugin
webpack通过plugin机制让其使用更加灵活,以适应各种应用场景,当然也大大增加了webpack的复杂性,在webpack运行的生命周期中会广播出许多事件,plugin可以hook这些事件,在合适的时机通过webpack提供的API改变其在处理过程中的输出结果。
WindRunnerMax
2021/10/09
9320
webpack 入门教程
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
老马
2018/08/20
4.3K0
webpack 入门教程
webpack的高阶使用
Webpack 是一款强大的模块打包工具,广泛应用于现代前端开发中。本文将从以下几个方面讨论 Webpack 的高阶使用方法:
世间万物皆对象
2024/03/20
1840
webpack Develoment 和 Production 模式的区分打包
代码已上传至github github代码地址:https://github.com/Miofly/mio.git webpack.common.js const merge = require('webpack-merge') const devConfig = require('./webpack.dev') const prodConfig = require('./webpack.prod') const commonConfig = { entry: { // 上面是简写
用户10106350
2022/10/28
3020
Webpack 使用详解
Webpack 是一个现代 JavaScript 应用程序的静态模块打包器。本文将详细介绍如何使用 Webpack,以及提供代码示例。为了保持篇幅,我们将简要介绍 Webpack 的核心概念和功能。
世间万物皆对象
2024/03/20
2120
从零认识webpack4.0,带你走进神秘的webpack
前言: 作为一个现代javascript 应用程序的静态模块打包器,webpack能将各种资源,如js,css, 图片等作为模块来处理,是当下前端工程化的一个很受欢迎的工具,webpack目前最新的版本是4.0,文章将在4.0 的基础上,从使用者的角度,一步步教你认识并搭建一个简单的webpack配置项目,当然webpack的配置和使用较为丰富且复杂。
前端老鸟
2019/07/29
5470
从零认识webpack4.0,带你走进神秘的webpack
Webpack5构造React多页面应用
来源 | https://github.com/zhedh/react-multi-page-app/
winty
2021/01/07
4K0
webpack从0到1构建
webpack是一个静态打包工具,根据入口文件构建一个依赖图,根据需要的模块组合成一个bundle.js或者多个bundle.js,用它来展示静态资源
Maic
2022/07/28
1.3K0
webpack从0到1构建
Webpack配置实战
本篇将从实践出发,搭建一个基础的支持模块化开发的项目,在第二章节《进阶配置》中使用 webpack 搭建一个 SASS + TS + React 的项目。
gogo2027
2022/10/17
1.4K0
相关推荐
【Webpack】320- Webpack4 入门手册(共 18 章)(下)
更多 >
LV.0
这个人很懒,什么都没有留下~
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验