【数据结构与算法】常用算法 前缀和

 🎉🎉欢迎光临🎉🎉

🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀

🌟特别推荐给大家我的最新专栏《数据结构与算法:初学者入门指南》📘📘

本专栏纯属为爱发电永久免费!!!

这是苏泽的个人主页可以看到我其他的内容哦👇👇

努力的苏泽http://suzee.blog.csdn.net

281d83d3df1a4544bdd00fdadf50950b.png

 

 

引言:


前缀和算法就是一种常用的算法,用于快速计算数组或序列中某一区间的和。它在很多问题中都有广泛的应用,例如求解子数组的最大和、区间和等。本文将介绍前缀和算法的原理及其应用。

  1. 问题背景:
    在很多计算问题中,我们需要频繁地计算数组或序列中某一区间的和。如果每次都遍历区间中的元素进行累加,时间复杂度会很高,效率低下。因此,我们需要一种更高效的方法来解决这个问题。

  2. 前缀和算法的作用:
    前缀和算法可以将数组或序列中的每个位置的元素累加起来,得到一个前缀和数组。利用前缀和数组,我们可以在O(1)的时间复杂度内计算任意区间的和,从而提高计算效率。

2.1 前缀和的定义:


对于一个给定的数组或序列,我们定义前缀和数组prefixSum,其中prefixSum[i]表示原数组中前i个元素的和。即prefixSum[i] = nums[0] + nums[1] + ... + nums[i-1]。特别地,prefixSum[0] = 0。

2.2 计算前缀和数组:


为了计算前缀和数组,我们可以从第一个元素开始遍历原数组,对于每个位置i,将前i个元素的和保存到prefixSum[i]中。具体的计算方法如下:

prefixSum[0] = 0
for i from 1 to n:prefixSum[i] = prefixSum[i-1] + nums[i-1]

其中,n表示数组的长度,nums表示原数组。

2.3 利用前缀和数组计算区间和:


利用前缀和数组,我们可以在O(1)的时间复杂度内计算任意区间的和。对于给定的区间[left, right],其中left表示区间的起始位置,right表示区间的结束位置,区间和可以通过前缀和数组计算得到:

sum[left, right] = prefixSum[right+1] - prefixSum[left]

其中,prefixSum[right+1]表示前right+1个元素的和,prefixSum[left]表示前left个元素的和。通过这个计算公式,我们可以快速得到任意区间的和。

3.1 子数组和的计算

def prefix_sum(nums):n = len(nums)prefix = [0] * (n + 1)for i in range(1, n + 1):prefix[i] = prefix[i - 1] + nums[i - 1]return prefixdef subarray_sum(nums, start, end):prefix = prefix_sum(nums)return prefix[end + 1] - prefix[start]

使用 prefix_sum 函数可以计算原始数组的前缀和数组 prefix。然后,通过计算 prefix[end + 1] - prefix[start],就可以得到从下标 start 到下标 end 的子数组和。

3.2 区间和的查询

def range_sum(prefix, start, end):return prefix[end + 1] - prefix[start]

在区间和的查询中,我们不需要每次都重新计算前缀和数组。我们可以直接使用已经计算好的前缀和数组 prefix,通过计算 prefix[end + 1] - prefix[start],即可得到从下标 start 到下标 end 的区间和。

3.3 数组元素的更新和查询

def update(prefix, index, value):prefix[index + 1] += valuedef query(prefix, index):return prefix[index + 1]

在数组元素的更新和查询中,我们可以直接通过修改前缀和数组 prefix 中的相应位置来实现。通过 prefix[index + 1] 可以查询下标 index 处的数组元素值,通过 prefix[index + 1] += value 可以更新下标 index 处的数组元素值。

4.1 前缀和数组的空间优化

def prefix_sum(nums):n = len(nums)prefix = [0] * nprefix[0] = nums[0]for i in range(1, n):prefix[i] = prefix[i - 1] + nums[i]return prefixdef subarray_sum(nums, start, end):prefix = prefix_sum(nums)if start == 0:return prefix[end]else:return prefix[end] - prefix[start - 1]

在前缀和数组的空间优化中,我们可以直接在原始数组 nums 上进行操作,而不需要额外的前缀和数组。在计算子数组和时,通过 prefix[end] - prefix[start - 1] 可以得到从下标 start 到下标 end 的子数组和,特别要注意边界情况。

4.2 优化区间和查询的时间复杂度

def prefix_sum(nums):n = len(nums)prefix = [0] * (n + 1)for i in range(1, n + 1):prefix[i] = prefix[i - 1] + nums[i - 1]return prefixdef range_sum(prefix, start, end):return prefix[end + 1] - prefix[start]def optimize_range_sum(prefix, start, end):return range_sum(prefix, start, end) if start == 0 else range_sum(prefix, start, end) - prefix[start]

在优化区间和查询的时间复杂度时,我们可以直接利用已经计算好的前缀和数组 prefix,通过 prefix[end + 1] - prefix[start] 可以得到从下标 start 到下标 end 的区间和。如果起始下标 start 不为0,我们可以通过 range_sum(prefix, start, end) - prefix[start] 计算区间和,避免重复计算前缀和。

4.3 前缀和数组的差分运算

def difference(nums):n = len(nums)dif = [0] * n
```python
def difference(nums):n = len(nums)dif = [0] * ndif[0] = nums[0]for i in range(1, n):dif[i] = nums[i] - nums[i - 1]return difdef update(dif, start, end, value):dif[start] += valueif end + 1 < len(dif):dif[end + 1] -= valuedef recover(nums, dif):n = len(nums)nums[0] = dif[0]for i in range(1, n):nums[i] = dif[i] + nums[i - 1]return nums

 

通过差分运算,我们可以将原始数组转化为差分数组 dif。差分数组的特点是,差分数组中的值表示原始数组中相邻元素的差值。通过 dif[i] = nums[i] - nums[i - 1],可以得到差分数组。在进行数组元素的更新时,我们只需要更新差分数组中的相应位置,而不需要修改原始数组。通过 update 函数可以更新差分数组的指定范围内的值。最后,通过 recover 函数可以根据差分数组恢复原始数组的值。

5.1 问题描述

假设给定一个整数数组 nums,我们需要找到该数组中连续子数组的最大和。

5.2 基本解法

def max_subarray_sum(nums):n = len(nums)max_sum = float('-inf')for i in range(n):current_sum = 0for j in range(i, n):current_sum += nums[j]max_sum = max(max_sum, current_sum)return max_sum

基本解法是使用双重循环来枚举所有可能的连续子数组,并计算它们的和。在计算过程中,记录最大的和,最后返回最大和。

5.3 利用前缀和算法的优化解法

def max_subarray_sum(nums):n = len(nums)prefix = [0] * (n + 1)max_sum = float('-inf')for i in range(1, n + 1):prefix[i] = prefix[i - 1] + nums[i - 1]for i in range(n):for j in range(i, n):current_sum = prefix[j + 1] - prefix[i]max_sum = max(max_sum, current_sum)return max_sum

优化解法利用了前缀和算法来减少计算子数组和的时间复杂度。首先,通过计算前缀和数组 prefix,可以在常数时间内得到任意区间的和。然后,使用双重循环来枚举所有可能的连续子数组,但是在计算过程中,通过前缀和数组直接计算子数组的和,而不需要每次都重新计算。最后返回最大和。

总结

6.1 前缀和算法的优点

  • 前缀和算法能够高效地计算数组或序列中某个区间的和,大大减少了重复计算的时间复杂度。
  • 前缀和算法适用于需要频繁查询区间和或数组元素的更新和查询的场景。
  • 前缀和算法可以通过差分运算来进一步优化,减少空间复杂度。

6.2 注意事项和适用范围

  • 在使用前缀和算法时,需要注意边界情况和数组下标的处理,确保计算的正确性。
  • 前缀和算法适用于静态数组,即数组元素在查询和更新操作之间不会发生改变的情况。
  • 如果数组元素会发生频繁的更新操作,需要使用差分运算来处理,以避免重复计算前缀和。

 

 

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

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

相关文章

离散数学——树思维导图

离散数学——树思维导图 文章目录 前言内容大纲参考 前言 这是当初学习离散数学时整理的笔记大纲&#xff0c;其中包含了自己对于一些知识点的体悟。现将其放在这里作为备份&#xff0c;也希望能够对你有所帮助。 当初记录这些笔记只是为了在复习时更快地找到对应的知识点。…

Python爬虫之极验滑动验证码的识别

极验滑动验证码的识别 上节我们了解了可以直接利用 tesserocr 来识别简单的图形验证码。近几年出现了一些新型验证码&#xff0c;其中比较有代表性的就是极验验证码&#xff0c;它需要拖动拼合滑块才可以完成验证&#xff0c;相对图形验证码来说识别难度上升了几个等级。本节将…

如何在Linux部署Portainer并结合内网穿透远程管理本地Docker容器

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 Portainer 是一个轻量级的容器管理工具&#xff0c;可以通过 Web 界面对 Docker 容器进行管理和监控。它提供了可…

用c# 自己封装的Modbus工具类库源码

前言 Modbus通讯协议在工控行业的应用是很多的&#xff0c;并且也是上位机开发的基本技能之一。相关的类库也很多也很好用。以前只负责用&#xff0c;对其并没有深入学习和了解。前段时间有点空就在这块挖了挖。想做到知其然还要知其所以然。所以就有了自己封装的Modbus工具类库…

Mysql 常用数据类型

数值型(整数)的基本使用 如何定义一个无符号的整数 数值型(bit)的使用 数值型(小数)的基本使用 字符串的基本使用 字符串使用细节 日期类型的基本使用

Orange3数据预处理(列选择组件)数据角色及类型描述

在Orange3的文件组件中&#xff0c;datetime、categorical、numeric以及text代表不同种类的数据类型&#xff0c;具体如下&#xff1a; datetime&#xff1a;代表日期和时间类型的数据。通常用于时间序列分析、生存分析和其他需要考虑时间因素的机器学习任务中。例如&#xff0…

图像读取裁剪与人脸识别

图像读取 Image read ⇒ \Rightarrow ⇒ torchvision.datasets from torchvision import datasets dataset datasets.ImageFolder(data_dir, transformtransforms.Resize((512, 512)))Return value illustration dataset[0][0]是PIL.Image objects&#xff0c;这利用IPyth…

小红书关键词爬虫

标题 1 统计要收集的关键词,制作一个文件夹2 爬取每一页的内容3 爬取标题和内容4 如果内容可以被查看,爬取评论内容5 将结果进行汇总,并且每个帖子保存为一个json文件,具体内容6 总结1 统计要收集的关键词,制作一个文件夹 例如,我要收集旅游相关的,就收集: 旅游、旅行…

关系型数据库事务的四性ACID:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)

关系型数据库事务的四性ACID:原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;和持久性&#xff08;Durability&#xff09; 事务的四性通常指的是数据库事务的ACID属性&#xff0c;包括原子性&…

Python从入门到精通指南【第101篇—入门到精通】【文末送书-24】

文章目录 Python从入门到精通指南第一步&#xff1a;入门基础1.1 安装Python1.2 Hello World1.3 变量和数据类型1.4 控制流程 第二步&#xff1a;深入学习2.1 函数和模块2.2 列表、元组和字典2.3 文件操作 第三步&#xff1a;高级主题3.1 面向对象编程3.2 异常处理3.3 正则表达…

大型电商日志离线分析系统(一)

一、项目需求分析 某大型网站日志离线分析系统 1.1 概述 该部分的主要目标就是描述本次项目最终七个分析模块的页面展示。 1.2 工作流 在我们的demo展示中&#xff0c;我们使用jqueryecharts的方式调用程序后台提供的rest api接口&#xff0c;获取json数据&#xff0c;然后…

《极简C++学习专栏》之结束语

朋友们&#xff0c;经过这么长的时间&#xff0c;《极简C学习专栏》的文章创作就要结束了&#xff0c;感谢你们一路陪伴&#xff01; 也希望你们能支持我接下来的其他专栏的创作&#xff01; 专栏的初衷 《极简C学习》专栏的初衷源自于我个人的学习笔记&#xff0c;记录下自己…

网络安全与信创产业发展:构建数字时代的护城河

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua&#xff0c;在这里我会分享我的知识和经验。&#x…

数字人的未来:数字人对话系统 Linly-Talker + 克隆语音 GPT-SoVITS

&#x1f680;数字人的未来&#xff1a;数字人对话系统 Linly-Talker 克隆语音 GPT-SoVITS https://github.com/Kedreamix/Linly-Talker 2023.12 更新 &#x1f4c6; 用户可以上传任意图片进行对话 2024.01 更新 &#x1f4c6; 令人兴奋的消息&#xff01;我现在已经将强…

Vue | (六)使用Vue脚手架(下)| 尚硅谷Vue2.0+Vue3.0全套教程

文章目录 &#x1f4da;Vue 中的自定义事件&#x1f407;使用方法&#x1f407;案例练习&#x1f407;TodoList案例优化 &#x1f4da;全局事件总线&#x1f407;使用方法&#x1f407;案例练习&#x1f407;TodoList案例优化 &#x1f4da;消息订阅与发布&#x1f407;使用方法…

嵌入式C语言(一)

最初我是golang出生&#xff0c;当时做项目的时候java、c、js、python都折腾过&#xff0c;但是关于c语言的接触&#xff0c;基本上都停留在大一的那个暑假。 后面一个项目需要写驱动&#xff0c;再到后门需要做DFX&#xff0c;再到我打开内核的源码&#xff0c;我一脸懵逼&am…

改进 RAG:自查询检索

原文地址&#xff1a;Improving RAG: Self Querying Retrieval 2024 年 2 月 11 日 让我们来解决构建 RAG 系统时的一个大问题。 我们不能依赖语义搜索来完成每个检索任务。只有当我们追求单词的含义和意图时&#xff0c;语义搜索才有意义。 But in case&#xff0c;我们正…

【读文献】DynamicBind生成式模型预测蛋白配体复合物

published at nature communication (2024.01.24) code link paper link 摘要 尽管在预测静态蛋白质结构方面取得了重大进展&#xff0c;但蛋白质的内在动态性&#xff0c;受到配体调节&#xff0c;对于理解蛋白质功能和促进药物发现至关重要。 传统的对接方法&#xff0c;常…

LCR 172. 统计目标成绩的出现次数

解题思路&#xff1a;二分查找 题解一 class Solution {public int countTarget(int[] scores, int target) {// 搜索右边界 rightint i 0, j scores.length - 1;while(i < j) {int m (i j) / 2;if(scores[m] < target) i m 1;else j m - 1;}int right i;// 若数…

wpf 简单实验 数据更新 列表更新

1.概要 1.1 需求 一个列表提供添加修改删除的功能&#xff0c;添加和修改的内容都来自一个输入框 1.2 要点 DisplayMemberPath"Zhi"列表.ItemsSource datalist;(列表.SelectedItem ! null)(列表.SelectedItem as A).Zhi 内容.Text;datalist.Remove((列表.Selec…