前缀和算法

news2024/9/29 1:26:49

目录

  • 1.概述
  • 2.代码实现
    • 2.1.一维前缀和
    • 2.2.二维前缀和
  • 3.应用

本文参考:
LABULADONG 的算法网站

1.概述

前缀和算法分为一维和二维,一维前缀和可以快速求序列中某一段的和,而二维前缀和可以快速求一个矩阵中某个子矩阵的和

2.代码实现

2.1.一维前缀和

(1)实现代码如下:

class NumArray {
    //前缀和数组,preSum[i] 表示 nums[0...i - 1] 的累加和
    private int[] preSum;
    
    //输入数组 nums,构造前缀和
    public NumArray(int[] nums) {
        // preSum[0] = 0,便于计算累加和
        preSum = new int[nums.length + 1];
        for (int i = 1; i < preSum.length; i++) {
            preSum[i] = preSum[i - 1] + nums[i - 1];
        }
    }
    
    //查询闭区间 nums[left, right] 的累加和
    public int sumRange(int left, int right) {
        return preSum[right + 1] - preSum[left];
    }
}

(2)下面对代码中一些细节进行说明:

  • 前缀和数组 preSum 的长度之所以设置为 nums.length + 1 而非 nums.length,其原因在于方便计算累加和;
  • preSum[i] 表示 nums[0…i - 1] 的累加和,那么推导出 preSum[i] = preSum[i - 1] + nums[i - 1],如下图所示:
    在这里插入图片描述
  • 在有了前缀和数组 preSum 后,如果想要查询区间 nums[i…j] 的累加和,那么计算 preSum[j + 1] - preSum[i] 的值即可,如下图所示:
    在这里插入图片描述

2.2.二维前缀和

(1)实现代码如下:

class NumMatrix {
    // preSum[i][j] 表示矩阵 matrix 中左上角坐标为 [0, 0]、右下角坐标为 [i - 1, j - 1] 的子矩阵的元素和
    private int[][] preSum;
    
    public NumMatrix(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        if (m == 0 || n == 0) {
            return;
        }
        //构造前缀和矩阵
        preSum = new int[m + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // 计算每个左上角坐标为 [0, 0]、右下角坐标为 [i - 1, j - 1] 的子矩阵的元素和
                preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + matrix[i - 1][j - 1] - preSum[i - 1][j - 1];
            }
        }
    }
    
    //计算矩阵 matrix 中左上角坐标为 [x1, y1]、右下角坐标为 [x2, y2] 的子矩阵的元素和
    public int sumRegion(int x1, int y1, int x2, int y2) {
        return preSum[x2 + 1][y2 + 1] - preSum[x1][y2 + 1] - preSum[x2 + 1][y1] + preSum[x1][y1];
    }
}

(2)下面对代码中一些细节进行说明:

  • 设下图中绿色子矩阵的左上角坐标为 [x1, y1]、右下角坐标为 [x2, y2],那么它可以由下图中右边的 4 个子矩阵通过加减组合得到:

在这里插入图片描述

  • 在初始化前缀和矩阵 preSum 时,需要计算每个左上角坐标为 [0, 0]、右下角坐标为 [i - 1, j - 1] 的子矩阵的元素和,此时只需要将上面的等式稍作变换即可,如下图所示。不过需要注意的是绿色子矩阵的边长为 1,即对应矩阵 matrix 中的一个元素

在这里插入图片描述

3.应用

(1)前缀和算法的使用场景:原数组/矩阵在不会被修改的前提下,频繁地对其某个区间/子矩阵的累加和进行查询操作。如果只需要查询一次,那么使用前缀和算法的意义不大;而如果频繁地进行查询操作,那么前缀和算法的优势便体现出来了:
① 在构建前缀和数组/矩阵时,其时间复杂度为 O(n) / O(mn),而在频繁地进行查询操作时,其时间复杂度仅为 O(1);
② 如果直接进行累加操作,则需要进行多次时间复杂度为 O(n) / O(mn) 的操作(注:此处的 n 和 mn 取决于要查询的区间 / 子矩阵大小)。

(2)下面以 LeetCode 中的304.二维区域和检索 - 矩阵不可变这题为例:

在这里插入图片描述

本题就是典型地要频繁地对其矩阵 matrix 中的子矩阵的累加和进行查询操作,其对应的实现代码如下:

class NumMatrix {
    /*
        前缀和矩阵preSum记录矩阵matrix[0,0,i,j]的元素和
        preSum[i][j]=左上角(0,0)、右下角(i-1,j-1)所描述的子矩阵的元素总和
    */
    private int[][] preSum;
    
    public NumMatrix(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        //构造前缀和矩阵
        preSum = new int[m + 1][n + 1];
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] + matrix[i - 1][j - 1] - preSum[i - 1][j - 1];
            }
        }
    }
    
    //计算左上角(row1, col1)、右下角(row2, col2)所描述的子矩阵的元素总和
    public int sumRegion(int row1, int col1, int row2, int col2) {
        return preSum[row2 + 1][col2 + 1] - preSum[row1][col2 + 1] - preSum[row2 + 1][col1] + preSum[row1][col1];
    }
}

/**
 * Your NumMatrix object will be instantiated and called as such:
 * NumMatrix obj = new NumMatrix(matrix);
 * int param_1 = obj.sumRegion(row1,col1,row2,col2);
 */

(3)读到这里,想必大家对前缀和算法有了一定的了解,大家可以去 LeetCode 上找相关的前缀和的题目来练习,或者也可以直接查看LeetCode算法刷题目录(Java)这篇文章中的前缀和的章节。如果大家发现文章中的错误之处,可在评论区中指出。

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

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

相关文章

约拍小程序开发,优化约拍产业路径

随着网红、直播经济的发展&#xff0c;年轻群体对于拍摄服务的需求正在急速增长&#xff0c;与此同时该群体用户又极具个性&#xff0c;很多传统影楼拍摄价格高、拍摄风格固定化、等待时间久&#xff0c;个人摄影师宣传推广难度又大&#xff0c;导致拍摄需求被抑制&#xff0c;…

_Linux多线程-基础篇

文章目录1. 什么是线程Linux中的线程叫做轻量级进程&#xff08;LWP&#xff09;2. 线程的优点3. 线程的缺点4. 线程异常5. 线程用途6. Linux进程VS线程单进程7. 总结线程在进程内部执行是OS调度的基本单位。不同视角看待进程轻量级进程1. 什么是线程 在一个程序里的一个执行路…

【Cfeng Work】 Open API的intro和 梳理

OpenAPI 开放平台 内容管理Open API intro腾讯云OpenAPIOpenAPI请求API密钥管理云API签名过程拼接规范请求串 CanonicalRequest拼接待签名字符串计算签名拼接到Authorization中云API签名失败规范Token 和 长期密钥公共参数OpenApi设计AppId、AppSecretsign签名timestamp 时间戳…

制造服务行业需要项目管理软件吗?

伴随着时代的快速发展&#xff0c;电子制造服务行业也正在飞速发展&#xff0c;在日新月异得时代步伐下&#xff0c;科学得管理方法和现代化得管理工具相结合&#xff0c;保证企业得进步与发展。项目管理工具通过构造高效统一的项目管理平台&#xff0c;优化企业管理中存在的问…

win10 conda安装labme安装和使用

1、安装conda 在WIN10中配置conda 1.1miniconda下载 https://docs.conda.io/en/latest/miniconda.html 可以任意选择对应的版本&#xff0c;安装时选择配置路径&#xff0c;以免后期重复配置环境。 1.2.2 在环境变量中添加路径 Win R&#xff0c;打开运行&#xff0c;输入…

在ubuntu系统上用pyinstaller加密打包yolov5项目代码的详细步骤

目录0. 背景1. 创建虚拟环境2. pyinstaller打包2.1. 生成并修改spec文件2.2. 重新生成二进制文件3. 测试4. 加密打包4.1. 创建入口函数main.py4.2. 修改detect.py4.3. 加密生成main.spec文件4.4. 修改main.spec文件4.5. 生成二进制文件4.6. 测试0. 背景 最近需要在ubuntu 18.0…

Payso×OceanBase:云上拓新,开启云数据库的智能托管

日前&#xff0c;聚合支付厂商 Payso&#xff08; 独角鲨北京科技有限公司&#xff09;的平台、交易系统引入 OceanBase 原生分布式数据库&#xff0c;实现显著降本增效—— 硬件成本降低 20&#xff5e;30%&#xff0c;查询效率提升 80%&#xff0c;执行效率提升了 30%&#x…

学习IB生物,我们需要知道什么知识点?

学习IB课程的很多同学应该都听说过一个说法&#xff1a;IB生物算是理科中的文科&#xff0c;没有公式推导&#xff0c;只有大量需要记忆的内容&#xff0c;不需要用学习理科的思维去学习&#xff0c;其实这种观点是有误区的。实际上&#xff0c;学习生物这门课将会面对的是一个…

01背包问题详解

目录 1.1二维dp数组 1.2一维dp数组改进 1.3相关例题 1.3.1分割等和子集 1.3.2一和零 1.1二维dp数组 概述&#xff1a;背包的最大重量是固定的&#xff0c;物品的数量&#xff0c;重量也是固定的&#xff0c;并且物品只能放一次&#xff0c;可以选择放或者不放&#xff0c…

Redis 核心原理串讲(中),架构演进之高可用

文章目录Redis 核心原理总览&#xff08;全局篇&#xff09;前言一、持久化1、RDB2、AOF3、AOF 重写4、混合持久化5、对比二、副本1、同步模式2、部分重同步三、哨兵1、核心能力2、节点通信总结Redis 核心原理总览&#xff08;全局篇&#xff09; 正文开始之前&#xff0c;我们…

【FPGA】Verilog:基本实验步骤演示 | 功能电路创建 | 添加仿真激励 | 观察记录仿真波形

前言&#xff1a; 本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载的完整过程、Verilog语言基本运用&#xff0c;电路设计和Test Bench程序的编写、以及实验开发板的使用&#xff0c;通过观察和数据记录理解仿真和FGPA实现的差异。 目录 Ⅰ. 基础知…

考研政治 马原 易混淆知识点

马哲 1. 哲学基本问题 从何者为第一性&#xff0c;分为唯物主义和唯心主义 从是否具有同一性&#xff0c;分为可知论&#xff08;有同一性&#xff09;和不可知论&#xff08;无同一性&#xff09; 辩证法&#xff1a;联系&#xff0c;发展的观点看世界&#xff0c;认为发展的…

python对接API二次开发高级实战案例解析:百度地图Web服务API封装函数(行政区划区域检索、地理编码、国内天气查询、IP定位、坐标转换)

文章目录前言一、IP定位1.请求URL2.获取IP定位封装函数3.输出结果二、国内天气查询1.请求url2.天气查询封装函数3.输出结果三、行政区划区域检索1.请求url2.区域检索封装函数3.输出结果四、地理编码1.请求url2.地理编码封装函数3.输出结果五、坐标转换1.请求url2.坐标转换封装函…

一文细说Linux虚拟文件系统原理

在 Unix 的世界里&#xff0c;有句很经典的话&#xff1a;一切对象皆是文件。这句话的意思是说&#xff0c;可以将 Unix 操作系统中所有的对象都当成文件&#xff0c;然后使用操作文件的接口来操作它们。Linux 作为一个类 Unix 操作系统&#xff0c;也努力实现这个目标。 虚拟…

CSS 这个就叫优雅 | 多行文本溢出省略

CSS 这个就叫优雅 | 多行文本溢出省略 文章目录CSS 这个就叫优雅 | 多行文本溢出省略一、文本溢出省略方式二、WebKit内核浏览器解决方法&#x1f959;三、通用解决方法四、CSS 预处理器封装&#x1f969;五、参考资料&#x1f498;六、推荐博文&#x1f357;一、文本溢出省略方…

小样本学习(Few-Shot Learning)训练参数意义

一、常规参数 1.1 epoch 是指所有的训练数据都要跑一遍。假设有6400个样本&#xff0c;在训练过程中&#xff0c;这6400个样本都跑完了才算一个epoch。一般实验需要训练很多个epoch&#xff0c;直到LOSS稳定后才停止。 1.2 batch_size 中文名称是批大小&#xff0c;之前的640…

【数据结构趣味多】二叉树概念及性质

1.树的定义 定义&#xff1a;树&#xff08;Tree&#xff09;是n&#xff08;n>0&#xff09;个结点的有限集。n0时称为空树。在任意一棵非空树种&#xff1b; 有且仅有一个根结点&#xff08;root&#xff09;。当n>1时&#xff0c;其余结点可分为m&#xff08;m>0&a…

H13-531云计算HCIE V2.0——400~600常错题和知识点总结

400~600 422、在 FusionCloud 6.x 中&#xff0c;以下关于备份的说法哪项是错误的&#xff1f; A&#xff0e;备份协议支持本地&#xff0c;通过 FTP/SFTP 到第三方服务器及 OBS B. 为了保证系统稳定运行&#xff0c;对管理数据进行备份恢复可以确保在异常时对业务的影响降到…

没有完美的项目,也轮不到你,找到适合自己的,先干起来再说

首先明确一点&#xff0c;没有百分百完美的项目&#xff0c;即使有&#xff0c;也轮不到你。不要认为你必须先找到一个完美的项目&#xff0c;然后再去工作。这个想法最后的结局就是项目一直在找&#xff0c;观望&#xff0c;迟迟不行动&#xff0c;不赚钱。如果你真的想找个项…

C++ 语法基础课 习题7 —— 类、结构体、指针、引用

文章目录例题1. 21.斐波那契数列2. 16.替换空格3. 84.123...n4. 28.O(1)时间删除链表结点5. 36.合并两个排序的链表例题 1. 21.斐波那契数列 Acwing 21.斐波那契数列 class Solution { public:int Fibonacci(int n) {if(n < 1) return n;return Fibonacci(n - 1) Fibon…