算法专题:前缀和

news2024/9/24 3:27:03

文章目录

    • Acwing:前缀和示例
    • 2845.统计趣味子数组的数目
      • 思路
      • 容易理解的写法:前缀和+两层循环
        • 存在问题:超时
      • 优化写法:两数之和思路,转换为哈希表

前缀和,就是求数组中某一段的所有元素的和

求子数组中某一段数字的元素和,只需要转换成两个数字的差值就可以了。

注意:

  • 只能求连续某一段区间的元素和
  • 一般来说前缀和需要在前面加一个0,因为表示成两个数字的差的话,如果前面不加0,带有第一个数字的元素和无法表示成差值,例如下图

在这里插入图片描述

Acwing:前缀和示例

在这里插入图片描述

  • 前缀和注意:需要在最前面加上一个0,所以前缀和数组大小是nums.size()+1
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int main()
{
    int n, m, l, r;
    scanf("%d%d", &n, &m);
    int a[n], sum[n + 1];     // s设置为n+1是为了后面计算方便
    
    for (int i = 0; i < n; i ++ ) 
        scanf("%d", &a[i]);
    
    sum[0] = 0;
    
    for (int i = 0; i < n; i ++ ) 
        sum[i + 1] = sum[i] + a[i];
    
    while (m -- ) {
        scanf("%d%d", &l, &r);
        printf("%d\n", sum[r] - sum[l - 1]);	// 这里的l和r是1~n范围
    }
    return 0;
}

  1. 读入两个整数 nmn 是数组 a 的大小,m 是查询的数量。
  2. 定义数组 asuma 用于存储输入的整数序列,sum 用于存储前缀和。
  3. 初始化 sum[0] 为0。
  4. 使用循环计算 sum 数组,其中 sum[i] 存储了数组 a 的前 i 个元素的和。
  5. 循环进行 m 次查询,每次查询读入两个整数 lr,然后输出区间 [l, r] 的和。这个和可以通过 sum[r] - sum[l - 1] 很快得到。注意,这里的 lr 是1-based,也就是从1开始的,而数组索引是0-based所以可以直接用sum[r]-sum[l-1],因为r本身已经是对应的下标+1了

代码示例中的 sum[r] - sum[l - 1] 是核心点。为了理解它,考虑下面的例子:

a:     2   3   4   5
sum:  0   2   5   9  14

为了得到 [2, 4]这里的下标r和l是从1开始的)子区间和 (即 3 + 4 + 5),我们可以使用 sum[4] - sum[2 - 1],结果为 12。

2845.统计趣味子数组的数目

给你一个下标从 0 开始的整数数组 nums ,以及整数 modulo 和整数 k

请你找出并统计数组中 趣味子数组 的数目。

如果 子数组 nums[l..r] 满足下述条件,则称其为 趣味子数组

  • 在范围 [l, r] 内,设 cnt 为满足 nums[i] % modulo == k 的索引 i 的数量。并且 cnt % modulo == k

以整数形式表示并返回趣味子数组的数目。

**注意:**子数组是数组中的一个连续非空的元素序列。

示例 1:

输入:nums = [3,2,4], modulo = 2, k = 1
输出:3
解释:在这个示例中,趣味子数组分别是: 
子数组 nums[0..0] ,也就是 [3] 。 
- 在范围 [0, 0] 内,只存在 1 个下标 i = 0 满足 nums[i] % modulo == k 。
- 因此 cnt = 1 ,且 cnt % modulo == k 。
子数组 nums[0..1] ,也就是 [3,2] 。
- 在范围 [0, 1] 内,只存在 1 个下标 i = 0 满足 nums[i] % modulo == k 。
- 因此 cnt = 1 ,且 cnt % modulo == k 。
子数组 nums[0..2] ,也就是 [3,2,4] 。
- 在范围 [0, 2] 内,只存在 1 个下标 i = 0 满足 nums[i] % modulo == k 。
- 因此 cnt = 1 ,且 cnt % modulo == k 。
可以证明不存在其他趣味子数组。因此,答案为 3 。

示例 2:

输入:nums = [3,1,9,6], modulo = 3, k = 0
输出:2
解释:在这个示例中,趣味子数组分别是: 
子数组 nums[0..3] ,也就是 [3,1,9,6] 。
- 在范围 [0, 3] 内,只存在 3 个下标 i = 0, 2, 3 满足 nums[i] % modulo == k 。
- 因此 cnt = 3 ,且 cnt % modulo == k 。
子数组 nums[1..1] ,也就是 [1] 。
- 在范围 [1, 1] 内,不存在下标满足 nums[i] % modulo == k 。
- 因此 cnt = 0 ,且 cnt % modulo == k 。
可以证明不存在其他趣味子数组,因此答案为 2 。

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9
  • 1 <= modulo <= 10^9
  • 0 <= k < modulo

思路

首先思路就是运用前缀和,单独开一个x数组遍历所有的nums[i],满足条件计数为1,不满足条件计数为0。

这样的话,子数组[l,r]内满足条件的数字个数,直接就是子数组对应的x数组区间的和

容易理解的写法:前缀和+两层循环

#include <vector>

class Solution {
public:
    long countInterestingSubarrays(std::vector<int>& nums, int modulo, int k) {
        int n = nums.size();
        
        // 创建一个数组x来标记哪些数字模`modulo`后等于k
        std::vector<int> x(n, 0);
        
        // 创建一个前缀和数组
        std::vector<int> sum(n + 1, 0);

        // ----------- 前缀和计算开始 -----------
        for (int i = 0; i < n; ++i) {
            // 如果当前数字模`modulo`后等于k,则在x数组中的对应位置标记为1
            if (nums[i] % modulo == k) x[i] = 1;
            
            // 计算前缀和:当前位置的前缀和等于上一个位置的前缀和加上x数组中的当前值
            sum[i + 1] = sum[i] + x[i];
        }
        // ----------- 前缀和计算结束 -----------
        
        // 初始化答案为0
        long ans = 0;
        
        // 使用两重循环来检查所有可能的子数组和
        for (int l = 0; l < n; ++l) {               // 子数组的开始位置
            for (int r = l + 1; r <= n; ++r) {      // 子数组的结束位置
                // 如果子数组的和模`modulo`后等于k,则增加答案的值
                if ((sum[r] - sum[l]) % modulo == k) ans++;
            }
        }

        // 返回答案
        return ans;
    }
};

存在问题:超时

这种写法因为子数组两边都不定,会超时,时间复杂度是O(n^2)。

在这里插入图片描述

优化写法:两数之和思路,转换为哈希表

因为上面写法出现了超时,我们可以用类似 两数之和 的套路,来优化时间复杂度,用map来减少一层循环

  • 两数之和的优化方法是,遍历到nums[i]的时候,先看看target-nums[i]是不是已经在map里面了如果在直接返回,不在就加到map里面,继续遍历数字。遍历完了数组之后一定会收集所有的相加=目标和的两数组合。

  • 本题的优化方法是,我们遍历sum[r]的时候,找满足sum[r] - sum[l]) % modulo == k条件的sum[l]是不是已经在哈希表里面了。哈希表map的作用是存放已经枚举过的sum

#include <vector>
#include <unordered_map>

class Solution {
public:
    long countInterestingSubarrays(std::vector<int>& nums, int modulo, int k) {
        int n = nums.size();
        
        // x是原始数组,sum是前缀和数组
        std::vector<int> x(n, 0);
        std::vector<int> sum(n + 1, 0);
        
        // 使用unordered_map存储各个余数的位置数量
        std::unordered_map<int, int> cnt;
        cnt[0] = 1;
        
        long ans = 0;
        
        for (int i = 0; i < n; ++i) {
            if (nums[i] % modulo == k) x[i] = 1;
            
            // 计算前缀和
            sum[i + 1] = (sum[i] + x[i]) % modulo;

            int r = sum[i + 1];
            
            // 此处的索引就是在找满足条件的sum[l],r就是之前版本的sum[r]
            //需要满足的式子是(sum[r] - sum[l]) % modulo == k
            //这里+modulo的目的是为了防止r-k是负数,+m再取余,结果还是0不会影响
            ans += cnt[(r - k + modulo) % modulo];
            
            // 更新哈希表中的计数,这里是在更新sum[r]进哈希表(对应之前版本)
            cnt[r]++;
        }
        
        return ans;
    }
};

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

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

相关文章

输运方程的推导

1 概述 对于流场中守恒的物理量&#xff0c;均可采用输运方程&#xff08;transport equation&#xff09;进行描述其随时间变化和在空间的分布规律。输运方程的通用形式为&#xff1a; 输运方程描述了流动过程中的物理量守恒&#xff0c;其包括瞬态&#xff08;transient&…

FPGA实战小项目2

基于FPGA的贪吃蛇游戏 基于FPGA的贪吃蛇游戏 基于fpga的数字密码锁ego1 基于fpga的数字密码锁ego1 基于fpga的数字时钟 basys3 基于fpga的数字时钟 basys3

ElMessageBox.prompt 点击确认校验成功后关闭

ElMessageBox.prompt(, 验证取货码, {inputPattern: /^.{1,20}$/,inputErrorMessage: 请输入取货码,inputPlaceholder: 请输入取货码,beforeClose: (action, instance, done) > {if (action confirm) {if (instance.inputValue) {let flag false;if (flag) {done()} else …

OpenCV(二十五):边缘检测(一)

目录 1.边缘检测原理 2.Sobel算子边缘检测 3.Scharr算子边缘检测 4.两种算子的生成getDerivKernels() 1.边缘检测原理 其原理是基于图像中灰度值的变化来捕捉图像中的边界和轮廓。梯度则表示了图像中像素强度变化的强弱和方向。 所以沿梯度方向找到有最大梯度值的像素&…

信息检索与数据挖掘 |(一)介绍

文章目录 &#x1f4da;信息检索&#x1f407;概念&#x1f407;结构化与非结构化数据&#x1f407;信息检索的基本假设&#x1f407;信息检索小结&#x1f407;附&#xff1a;IR新课题 &#x1f4da;数据挖掘&#x1f407;定义&#x1f407;数据挖掘 vs 机器学习 &#x1f4da…

论文笔记:一分类及其在大数据中的潜在应用综述

0 概述 论文&#xff1a;A literature review on one‑class classification and its potential applications in big data 发表&#xff1a;Journal of Big Data 在严重不平衡的数据集中&#xff0c;使用传统的二分类或多分类通常会导致对具有大量实例的类的偏见。在这种情况…

2023 大学生数学建模竞赛-C题-第一问

题目&#xff1a; 在生鲜商超中&#xff0c;一般蔬菜类商品的保鲜期都比较短&#xff0c;且品相随销售时间的增加而变差&#xff0c; 大部分品种如当日未售出&#xff0c;隔日就无法再售。因此&#xff0c;商超通常会根据各商品的历史销售和需 求情况每天进行补货。 由于商超销…

深入浅出PyTorch函数torch.rand与torch.randn

torch.rand 和 torch.randn 都是PyTorch中用于生成随机张量的函数&#xff0c;但它们生成随机数的方式有所不同。 一、torch.rand torch.rand 生成在区间 [0, 1) 内均匀分布的随机数。 size 参数是一个表示所需张量形状的元组或整数。可以生成任何形状的随机张量。 二、torch.…

1、Flutter移动端App实战教程【环境配置、模拟器配置】

一、概述 Flutter是Google用以帮助开发者在IOS和Android 两个平台开发高质量原生UI的移动SDK&#xff0c;一份代码可以同时生成IOS和Android两个高性能、高保真的应用程序。 二、渲染机制 之所以说Flutter能够达到可以媲美甚至超越原生的体验&#xff0c;主要在于其拥有高性…

相似性搜索,第 4 部分:分层可导航小世界 (HNSW)

一、说明 SImilarity 搜索是一个问题&#xff0c;给定一个查询的目标是在所有数据库文档中找到与其最相似的文档。相似度搜索&#xff08;similarity search&#xff09;是指在大规模数据集中寻找与某个查询对象最相似的对象的过程。该过程通常涉及计算两个对象之间的相似度得分…

软件设计师学习笔记9-进程调度

目录 1. PV操作 1.1进程的同步与互斥 1.1.1互斥 1.1.2同步 1.2 PV操作 1.2.1信号量 1.2.2 PV操作的概念 2.信号量与PV操作 2.1 PV操作与互斥模型 2.2 PV操作与同步模型 2.3 互斥与同步模型结合 3.前趋图与PV操作 1. PV操作 1.1进程的同步与互斥 1.1.1互斥 互斥&…

Car Window Control Reset

大众汽车窗口自动升降失效&#xff0c;重置&#xff1a; 扣住5秒&#xff0c;重启汽车&#xff0c;试一下车钥匙&#xff0c;和再重试这个按钮&#xff0c;扣一下试一试

使用openWRT 配置SFTP 实现远程文件安全传输

文章目录 前言 1. openssh-sftp-server 安装2. 安装cpolar工具3.配置SFTP远程访问4.固定远程连接地址 前言 本次教程我们将在OpenWRT上安装SFTP服务&#xff0c;并结合cpolar内网穿透&#xff0c;创建安全隧道映射22端口&#xff0c;实现在公网环境下远程OpenWRT SFTP&#xf…

nginx空字节漏洞复现

将nginx复制到C盘根目录 cmd运行startup.bat 安装完成后访问 输入info.php 输入info.png 抓包使用00截断 可以看到phpinfo成功执行 在PHP的底层C语言里&#xff0c;%00代表着字符串结束&#xff0c;00截断可以用来绕过后端验证&#xff0c;后端验证的时候因为00截断认为文件是…

【已更新代码图表】2023数学建模国赛E题python代码--黄河水沙监测数据分析

E 题 黄河水沙监测数据分析 黄河是中华民族的母亲河。研究黄河水沙通量的变化规律对沿黄流域的环境治理、气候变 化和人民生活的影响&#xff0c;以及对优化黄河流域水资源分配、协调人地关系、调水调沙、防洪减灾 等方面都具有重要的理论指导意义。 附件 1 给出了位于小浪底水…

postgresql-使用plpgsql批量插入用户测试数据

目的 使用plpgsql批量插入用户测试数据 ❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤我是分割线❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤ 我的环境 客户端&#xff1a;windows 版pgadmin4 服务端&#xff1a;linux版PostgreSQL 15.4 ❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤…

Spring整合tomcat的WebSocket详细逻辑(图解)

主要解决存在的疑问 为什么存在2种spring整合websocket的方式&#xff0c;一种是使用ServerEndpoint注解的方式&#xff0c;一种是使用EnableWebSocket注解的方式&#xff0c;这2种有什么区别和联系&#xff1f;可以共存吗&#xff1f;它们实现的原理是什么&#xff1f;它们的各…

数据接口工程对接BI可视化大屏(二)创建BI空间

第2章 创建BI空间 2.1 SugarBI介绍 网站地址:https://cloud.baidu.com/product/sugar.html SugarBI是百度推出的自助BI报表分析和制作可视化数据大屏的强大工具。 基于百度Echarts提供丰富的图表组件&#xff0c;开箱即用、零代码操作、无需SQL&#xff0c;5分钟即可完成数…

C#__线程的优先级和状态控制

线程的优先级&#xff1a; 一个CPU同一时刻只能做一件事情&#xff0c;哪个线程优先级高哪个先运行&#xff0c;优先级相同看调度算法。 在Thread类中的Priority属性&#xff08;Highest,Above,Normal,BelowNormal,Lowest&#xff09;可以影响线程的优先级 关于…

PHP反序列化漏洞

一、序列化&#xff0c;反序列化 序列化&#xff1a;将php对象压缩并按照一定格式转换成字符串过程反序列化&#xff1a;从字符串转换回php对象的过程目的&#xff1a;为了方便php对象的传输和存储 seriallize() 传入参数为php对象&#xff0c;序列化成字符串 unseriali…