优选算法的睿智之林:前缀和专题(一)

news2025/3/25 16:25:02

专栏:算法的魔法世界

个人主页:手握风云

目录

一、前缀和

二、例题讲解

2.1. 一维前缀和

2.2. 二维前缀和

2.3. 寻找数组的中心下标

2.4. 除自身以外数组的乘积


一、前缀和

        前缀和算法是一种用于处理数组或序列数据的算法,其核心思想是通过预先计算出数组中每个位置之前所有元素的和(即前缀和),从而快速解决一些与区间和相关的问题。它在处理数组求和、区间统计等场景下非常高效。

二、例题讲解

2.1. 一维前缀和

        我们需要注意一个细节,上面题目的数组给定下标是从1开始的。我们先来想一个暴力解法——模拟。每次查询都从l下标一直遍历到r下标,最坏情况下就是q次都是从头遍历到尾,所以暴力解法的时间复杂度为O(n*q),n、q的最大值都为10^{5},一定会超时。

        第二种解法就是利用前缀和算法。第一步,我们先预处理出一个前缀和数组int[] dp,dp[i]代表的是arr数组区间[1,i]的和。而数组dp中每一个元素的算法不用再从头加到尾,直接利用递推公式dp[i] = dp[i-1] + arr[i]。

        第二步是利用前缀和数组。比如我们要计算[2,5]区间的和,我们没必要直接访问下标2——5。根据下图可以得出,dp[r] - dp[l-1]。我们预处理前缀和的时间复杂度为O(n),每次查询可以直接获取下标,那么q次查询的时间复杂度为O(q*1),整体时间复杂度为O(n)+O(q)

        前面提到了一个细节,就是数组下标为什么要从1开始?如果我们要查询[0,2]区间的和,那么l-1就会为-1,就会无法访问到数组的第一个元素,从而方便处理边界问题。

        完整代码实现:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNextInt()) {
            int n = in.nextInt(), q = in.nextInt();
            int[] arr = new int[n + 1];
            for (int i = 1; i < n + 1; i++) {
                arr[i] = in.nextInt();
            }

            //预处理一个前缀和数组
            long[] dp = new long[n + 1];
            for (int i = 1; i < n + 1; i++) {
                dp[i] = dp[i - 1] + arr[i];
            }

            //使用前缀和数组
            while (q > 0) {
                int l = in.nextInt(), r = in.nextInt();
                System.out.println(dp[r] - dp[l - 1]);
                q--;
            }
        }
    }
}

2.2. 二维前缀和

        暴力解法与上一道题一样,也是利用模拟在指定区间内遍历,时间复杂度为O(n*m*q)。跟上一道题一样,也是会超时的。

        同一维前缀和一样,我们第一步还是先预处理一个与给定矩阵arr[][]同等规模的前缀和矩阵。dp[i][j]里的每个元素代表着矩阵arr[][]的阴影面积。

        关于如何求出dp[i][j]的值,我们没有必要再去遍历矩阵arr,因为遍历的时间复杂度会与暴力求解的一样高。我们可以利用完全平方公式的思想,下图中的元素之和,就是四个区域A、B、C、D的和。A区域的和可以很好的算出来:dp[i-1][j-1],但是B、C区域的和又不好算了。我们退而求其次,利用A+B+A+C-A的来算。A+B:dp[i-1][j];A+C:dp[i][j-1]。

        第二步就是利用二维前缀和矩阵。题目要求我们算出(x1,y1)——(x2,y2)里面的值直接A+B+C+D-(A+B)-(A+C)+A求出结果。

        完整代码实现:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        //1. 读取输入的数据
        int n = in.nextInt(), m = in.nextInt(), q = in.nextInt();
        int[][] arr = new int[n + 1][m + 1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                arr[i][j] = in.nextInt();
            }
        }

        //2. 预处理一个前缀和矩阵
        long[][] dp = new long[n + 1][m + 1];
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1] + arr[i][j] - dp[i - 1][j - 1];
            }
        }

        //3. 使用前缀和矩阵
        while (q-- > 0) {
            int x1 = in.nextInt(), y1 = in.nextInt(), x2 = in.nextInt(), y2 = in.nextInt();
            System.out.println(dp[x2][y2] - dp[x1 - 1][y2] - dp[x2][y1 - 1] + dp[x1 - 1][y1 - 1]);
        }
    }
}

2.3. 寻找数组的中心下标

        本题是要我们查找一个下标,这个下标左侧的元素之和与右侧的元素之和相等。如果存在这样一个下标则返回这个下标值,如果没有返回-1。

        我们先来思考暴力解法。枚举每一个下标,计算左侧的元素之和与右侧的元素之和是否相等。我们需要从头到尾遍历数组下标,再去遍历左侧和右侧的元素,所以时间复杂度为O(n^{2})

        接下来对暴力解法进行优化。我们需要求的是某段数组元素的和,那么就可以利用前缀和思想,i左侧的元素之和f(i) = f(i-1) + nums[i-1],i右侧的元素之和g(i) = g(i+1) + nums[i+1]。只要比较出f(i) = g(i),就返回i。

        还有一些细节:1. 防止数组越界访问,如果i=0,那么f(i-1)就是[-1,0]这段区间的和,f(0)=0;同理,g(n-1)=0。2. f是依赖与i-1,所以f数组是从左向右填写;g是依赖于i+1,所以g数组是从右向左填写的。

        完整代码实现:

public class Solution {
    public int pivotIndex(int[] nums) {
        int n = nums.length;
        int[] f = new int[n];
        int[] g = new int[n];

        //预处理前缀和数组
        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++) {
            if (f[i] == g[i]) {
                return i;
            }
        }
        return -1;
    }
}

2.4. 除自身以外数组的乘积

        暴力解法与上一题类似,枚举数组下标,再遍历下标的左右两侧计算乘积。时间复杂度也与上一题一样,也是O(n^{2})

        利用前缀和的思想,预处理出i左侧区间的乘积和右侧区间的乘积,到某个下标时,直接从前缀与后缀里进行拿值就可以。算法原理与上一题完全一样的,只不过这道题是要求乘积。前缀积f[i] = f[i - 1] * nums[i - 1];g[i] = g[i+1] * nums[i+1]。细节处理上,与上一题不同的是,边界f[0]与g[n-1]要赋值成1。

        完整代码实现:

public class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n = nums.length;
        int[] f = new int[n];
        int[] g = new int[n];

        f[0] = 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];
        int[] ret = new int[n];
        for (int i = 0; i < n; i++)
            ret[i] = f[i] * g[i];
        return ret;
    }
}

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

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

相关文章

【清华大学】AIGC发展研究(3.0版)

目录 AIGC发展研究报告核心内容一、团队简介二、AI哲学三、国内外大模型四、生成式内容&#xff08;一&#xff09;文本生成&#xff08;二&#xff09;图像生成&#xff08;三&#xff09;音乐生成&#xff08;四&#xff09;视频生成 五、各行业应用六、未来展望 AIGC发展研究…

JavaSE1.0(基础语法之运算符)

算术运算符 基础运算之加 减 乘 除 取余&#xff08; - * / %&#xff09; 运算符之相加&#xff08; &#xff09; public static void main(String[] args) {System.out.println("Hello world!");int a 10;int b 20;int c a b;System.out.println(c);//…

蓝桥与力扣刷题(蓝桥 数的分解)

题目&#xff1a;把 2019分解成 3个各不相同的正整数之和&#xff0c;并且要求每个正整数都不包含数字 2 和 4&#xff0c;一共有多少种不同的分解方法&#xff1f; 注意交换 3 个整数的顺序被视为同一种方法&#xff0c;例如 1000100118和 1001100018 被视为同一种。 解题思…

Java IO 流:从字节到字符再到Java 装饰者模式(Decorator Pattern),解析与应用掌握数据流动的艺术

在 Java 编程中&#xff0c;IO&#xff08;输入输出&#xff09;流是处理数据输入输出的核心工具。无论是读取文件、网络通信&#xff0c;还是处理用户输入&#xff0c;IO 流都扮演着重要角色。本文将深入探讨 Java IO 流的核心概念、分类、经典代码实例及其应用场景&#xff0…

爬虫案例-爬取某站视频

文章目录 1、下载FFmpeg2、爬取代码3、效果图 1、下载FFmpeg FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。 点击下载: ffmpeg 安装并配置 FFmpeg 步骤&#xff1a; 1.下载 FFmpeg&#xff1a; 2.访问 FFmpeg 官网。 3.选择 Wi…

nacos-未经授权创建用户漏洞

1、修改配置文件 vim application.properties# 修改配置项 nacos.core.auth.enabledtrue nacos.core.auth.enable.userAgentAuthWhitefalse2、重启nacos systemctl restart nacos3、验证 打开nacos部署服务器输入命令 curl -XPOST -d “usernametest123&passwordtest!123…

C++:IO库

一、C IO库的架构 C标准库中的IO系统基于流&#xff08;Stream&#xff09;​的概念&#xff0c;分为三层结构&#xff1a; ​流对象​&#xff08;如cin, cout, fstream&#xff09;​流缓冲区​&#xff08;streambuf&#xff0c;负责底层数据处理&#xff09;​数据源/目的…

企业级前端架构设计与实战

一、架构设计核心原则 1.1 模块化分层架构 典型目录结构&#xff1a; src/├── assets/ # 静态资源├── components/ # 通用组件├── pages/ # 页面模块├── services/ # API服务层├── store/ # 全局状态管理├── uti…

从入门到精通【MySQL】 CRUD

文章目录 &#x1f4d5;1. Create 新增✏️1.1 单行数据全列插入✏️1.2 单行数据指定列插入✏️1.3 多行数据指定列插入 &#x1f4d5;2. Retrieve 检索✏️2.1 全列查询✏️2.2 指定列查询✏️2.3 查询字段为表达式✏️2.4 为查询结果指定别名✏️2.5 结果去重查询 &#x1f…

08_双向循环神经网络

双向网络 概念 双向循环神经网络&#xff08;Bidirectional Recurrent Neural Network, BiRNN&#xff09;通过同时捕捉序列的正向和反向依赖关系&#xff0c;增强模型对上下文的理解能力。与传统的单向网络不同,BIRNN 能够同时从过去和未来的上下文信息中学习,从而提升模型的…

2025年Postman的五大替代工具

虽然Postman是一个广泛使用的API测试工具&#xff0c;但许多用户在使用过程中会遇到各种限制和不便。因此&#xff0c;可能需要探索替代解决方案。本文介绍了10款强大的替代工具&#xff0c;它们能够有效替代Postman&#xff0c;成为你API测试工具箱的一部分。 什么是Postman&…

(四)---四元数的基础知识-(定义)-(乘法)-(逆)-(退化到二维复平面)-(四元数乘法的导数)

使用四元数的原因 最重要的原因是因为传感器的角速度计得到的是三个轴的角速度, 这三个轴的角速度合成一个角速度矢量, 结果就是在微小时间内绕着这个角速度矢量方向为轴旋转一定角度. 截图来源网址四元数 | Crazepony开源四轴飞行器

汇能感知高品质的多光谱相机VSC02UA

VSC02UA概要 VSC02UA是一款高品质的200万像素的光谱相机&#xff0c;适用于工业检测、农业、医疗等领域。VSC02UA 包含 1600 行1200 列有源像素阵列、片上 10 位 ADC 和图像信号处理器。它带有 USB2.0 接口&#xff0c;配合专门的电脑上位机软件使用&#xff0c;可进行图像采集…

Blazor+PWA技术打造全平台音乐播放器-从音频缓存到离线播放的实践之路

开局三张图… 0.起源 主要是自己现在用的是苹果手机&#xff0c;虽然手机很高级&#xff0c;但是想听自己喜欢的歌曲确是不容易&#xff0c;在线app都要付费&#xff0c;免费的本地播放器都不太好用&#xff08;收费的也不太行&#xff09;&#xff0c;基础功能都不满足。此外…

使用LangChain开发智能问答系统

代码地址见文末 1. 项目配置 1.1 Neo4j 数据库配置 1. 安装与环境变量 解压路径:将neo4j-community-5.x.x.zip解压至D:\neo4j-community-5.x.x环境变量: NEO4J_HOME: D:\neo4j-community-5.x.xJAVA_HOME: D:\neo4j-community-5.x.x\jdk(注意:需指向 JDK 目录)Path 变量…

Centos操作系统安装及优化

Centos操作系统安装及优化 零、环境概述 主机名 centos版本 cpu 内存 Vmware版本 ip地址 test CentOS Linux release 7.6.1810 (Core) 2C 2G 15.5.1 10.0.0.10 一、介质下载 1、7.6版本下载 CentOS7.6标准版下载链接: https://archive.kernel.org/centos-vault/7.6.1810/i…

游戏引擎学习第177天

仓库:https://gitee.com/mrxiao_com/2d_game_4 今日计划 调试代码有时可能会非常困难&#xff0c;尤其是在面对那些难以发现的 bug 时。显然&#xff0c;调试工具是其中一个非常重要的工具&#xff0c;但在游戏开发中&#xff0c;另一个非常常见的工具就是自定义的调试工具&a…

数据结构知识点1

目录 一、时间复杂度和空间复杂度 1.1时间复杂度&#xff1a; 1.2空间复杂度&#xff1a; 二、装箱和拆箱 三、泛型 3.1泛型类的使用&#xff1a; 3.2泛型的上界&#xff1a; 3.3泛型方法&#xff1a; 一、时间复杂度和空间复杂度 1.1时间复杂度&#xff1a; 时间复杂…

自由学习记录(45)

顶点片元着色器&#xff08;important&#xff09; 1.需要在Pass渲染通道中编写着色器逻辑 2.可以使用cG或HLSL两种shader语言去编写Shader逻辑 3.代码量较多&#xff0c;灵活性较强&#xff0c;性能消耗更可控&#xff0c;可以实现更多渲染细节 4.适用于光照处理较少&#xf…

数据源支持远程Excel/CSV,数据集支持分组字段功能,DataEase开源BI工具v2.10.6 LTS版本发布

2025年3月17日&#xff0c;人人可用的开源BI工具DataEase正式发布v2.10.6 LTS版本。 这一版本的功能变动包括&#xff1a;数据源方面&#xff0c;新增支持远程Excel/CSV数据源&#xff0c;支持以HTTP、HTTPS、FTP协议获取远程服务器上的Excel和CSV数据文件&#xff0c;并且可以…