算法专题:前缀和

文章目录

    • 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`后等于kstd::vector<int> x(n, 0);// 创建一个前缀和数组std::vector<int> sum(n + 1, 0);// ----------- 前缀和计算开始 -----------for (int i = 0; i < n; ++i) {// 如果当前数字模`modulo`后等于k,则在x数组中的对应位置标记为1if (nums[i] % modulo == k) x[i] = 1;// 计算前缀和:当前位置的前缀和等于上一个位置的前缀和加上x数组中的当前值sum[i + 1] = sum[i] + x[i];}// ----------- 前缀和计算结束 -----------// 初始化答案为0long 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.rhkb.cn/news/124421.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++基础】类与对象(中):默认成员函数、构造函数、析构函数、拷贝构造、赋值重载函数……

​&#x1f47b;内容专栏&#xff1a; C/C编程 &#x1f428;本文概括&#xff1a; C基础语法。六大默认构造函数简介、构造函数、析构函数、拷贝构造函数、赋值重载函数、const成员函数、取地址重载等。 &#x1f43c;本文作者&#xff1a; 阿四啊 &#x1f438;发布时间&…

K8S:kubeadm搭建K8S+Harbor 私有仓库

文章目录 一.部署规划1.主机规划2.部署流程 二.kubeadm搭建K8S1.环境准备2.安装docker3. 安装kubeadm&#xff0c;kubelet和kubectl4.部署K8S集群&#xff08;1&#xff09;初始化&#xff08;2&#xff09;部署网络插件flannel&#xff08;3&#xff09;创建 pod 资源 5.部署 …

网络编程套接字,Linux下实现echo服务器和客户端

目录 1、一些网络中的名词 1.1 IP地址 1.2 端口号port 1.3 "端口号" 和 "进程ID" 1.4 初始TCP协议 1.5 UDP协议 2、socket编程接口 2.1 socket 常见API 2.2 sockaddr结构 3、简单的网络程序 3.1 udp实现echo服务器和客户端 3.1.1 echo服务器实…

C++ 数组

C 数组 C 支持数组数据结构&#xff0c;它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据&#xff0c;但它往往被认为是一系列相同类型的变量。 数组的声明并不是声明一个个单独的变量&#xff0c;比如 number0、number1、...、number99&#xff0…

爬虫逆向实战(30)-某查查股东关联公司(HmacSHA512)

一、数据接口分析 主页地址&#xff1a;某查查 1、抓包 通过抓包可以发现数据接口是api/people/getRelatCompany 2、判断是否有加密参数 请求参数是否加密&#xff1f; 无 请求头是否加密&#xff1f; 通过查看“标头”可以发现&#xff0c;请求头中有一个key和value都是…

记一次生产环境服务卡死排查记录

接现场运维报告某java服务CPU狂飙&#xff0c;服务处于卡死无响应状态 询问现场运维什么场景造成的&#xff0c;答复是偶发现象&#xff0c;没有规律&#xff0c;和请求高峰期并没有关系。 因为服务是负载均衡的&#xff08;A、B两台&#xff09;&#xff0c;临时处理让运维重…

【网络通信 -- WebRTC】FlexFec 基本知识点总结概述

【网络通信 -- WebRTC】FlexFec 基本知识点总结概述 【1】FlexFec 的保护方案 假设存在一组源数据包(D L)&#xff0c;其序列号从 1 开始运行到 D L 一维非交错行 FEC(1-D Non-interleaved Row FEC) : 一种连续的源数据包进行保护的方案&#xff0c;可用于恢复按行分组的源…

LaTeX总结-2023年9月8日

1. LaTeX总结 文章目录 1. LaTeX总结1.1. 定义作者&#xff0c;通讯作者&#xff0c;地址&#xff0c;宏包1.1.1. Example 11.1.2. Example 21.1.3. 特殊符号——作者标注注 1.2. 调整字体1.2.1. 数学模式下使用正体1.2.2. LaTeX内使用中文1.2.3. 正文文字 1.3. 常用符号及字母…

专业游戏翻译公司怎么选择比较合适

近年来&#xff0c;游戏行业持续繁荣&#xff0c;市场需求也在不断扩大&#xff0c;其中游戏翻译的需求越来越旺盛。无论是引进游戏还是让游戏走向国际市场&#xff0c;都需要专业的翻译公司来帮忙。那么&#xff0c;怎么选择合适的游戏翻译公司呢&#xff1f;让我们一起来看看…

大数据技术之Hadoop:HDFS存储原理篇(五)

目录 一、原理介绍 1.1 Block块 1.2 副本机制 二、fsck命令 2.1 设置默认副本数量 2.2 临时设置文件副本大小 2.3 fsck命令检查文件的副本数 2.4 block块大小的配置 三、NameNode元数据 3.1 NameNode作用 3.2 edits文件 3.3 FSImage文件 3.4 元素据合并控制参数 …

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

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

小白备战大厂算法笔试(三)——栈、队列、双向队列

文章目录 栈栈常用操作栈的实现基于链表的实现基于数组的实现 两种实现对比栈典型应用 队列队列常用操作队列实现基于链表的实现基于数组的实现 队列典型应用 双向队列双向队列常用操作双向队列实现基于双向链表的实现基于数组的实现 双向队列应用 栈 栈是一种遵循先入后出的逻…

CVE-2017-12149

春秋云镜 CVE-2017-12149 JBoss反序列化漏洞 靶标介绍 2017年8月30日&#xff0c;厂商Redhat发布了一个JBOSSAS 5.x 的反序列化远程代码执行漏洞通告。该漏洞位于JBoss的HttpInvoker组件中的 ReadOnlyAccessFilter 过滤器中&#xff0c;其doFilter方法在没有进行任何安全检查…

算法通关村第十三关——溢出问题处理模板

前言 溢出问题是面试当中输出涉及到数字的一个需要特别注意的地方&#xff0c;典型的题目有三个&#xff1a;数字反转&#xff0c;将字符串转成数字和回文数。 1.整数反转 力扣7题&#xff0c;给你一个 32 位的有符号整数 x &#xff0c;返回将 x 中的数字部分反转后的结果。…

rk3399 linux 5.10 usb 2.0设备上电概率性注册失败

多次开关机&#xff0c;发现usb hub和4G都通信失败了&#xff0c;这就有点奇怪了&#xff0c;按理说usb驱动是没啥问题的 先查看usb log rootlinaro-alip:/# dmesg | grep usb [ 1.723797] usbcore: registered new interface driver usbfs [ 1.723828] usbcore: regis…

在很多公司里面会使用打tag的方式保留版本

&#xff1a;git tag|grep "xxx-dev“等分支来查看 2&#xff1a;git cherry-pick XXXXX 然后就是查看有冲突这些 git status 会出现相关的异常 然后解决相关的冲突 git add . git cherry-pick --continue git push XXX HEAD:refs/for/XXX 第一&#xff1a;git ta…

【LeetCode-中等题】17. 电话号码的字母组合

文章目录 题目方法一&#xff1a;递归回溯 题目 方法一&#xff1a;递归回溯 参考讲解&#xff1a;还得用回溯算法&#xff01;| LeetCode&#xff1a;17.电话号码的字母组合 首先可以画出树图&#xff1a; 先将数字对应的字符集合 加入到一个map集合 这里需要一个index来控…

伪静态web.config常见规则写法与参数介绍说明

伪静态web.config常见规则写法与参数介绍说明. 示例1&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <configuration><system.webServer><rewrite><rules><rule name"规则 1" stopProcessing"tru…

【AI理论学习】语言模型:从Word Embedding到ELMo

语言模型&#xff1a;从Word Embedding到ELMo ELMo原理Bi-LM总结参考资料 本文主要介绍一种建立在LSTM基础上的ELMo预训练模型。2013年的Word2Vec及2014年的GloVe的工作中&#xff0c;每个词对应一个vector&#xff0c;对于多义词无能为力。ELMo的工作对于此&#xff0c;提出了…

Go 接口和多态

在讲解具体的接口之前&#xff0c;先看如下问题。 使用面向对象的方式&#xff0c;设计一个加减的计算器 代码如下&#xff1a; package mainimport "fmt"//父类&#xff0c;这是结构体 type Operate struct {num1 intnum2 int }//加法子类&#xff0c;这是结构体…