算法基础1.7离散化
前言
离散化我感觉基本思路就是找有效信息然后映射,有那么一点点稀疏数组的感觉,实际上y总当时也说离散化的使用场景是针对于比较稀疏的数组使用
其实思路不是很难,但是实现起来还是有一定难度的,课后练习题的代码长度也是目前最长的吧好像
正文
大致介绍
离散化通常是针对于那些值域很大,比如1e9;但是有效数据不是很多,比如1e5的情况
我们可以把这有效的1e5个数映射到一个新的数组里面,依次对应从0开始的自然数,所以目前(我所学的)是针对于整数的离散化。
这次我们从题目分析开始,来了解离散化的意义。
初见这道题,看到他是对数组中几个数进行加法操作,最后求一个区间内所有数的和,其实最容易想到的就是前缀和。实际上这道题确实要使用前缀和,但是由于数组过大(虽然给了一个很大的数据范围,但是题目还专门用“无限长”来再次强调这个数组有多么长),所以单纯使用数组绝对会爆的。
而这里面的思想就和我们的稀疏数组很像了,由于所有位置的初始值都是0,我们只对部分位置的值进行了修改,所以实际上绝大部分位置是没有记录的必要性的。我们只需要记录下那些修改的位置,在最后处理的时候对于那些没有变更的位置做统一处理即可。
数组处理思路:
- 我们把所有有效位置的位置值记录下来放到
alls
数组中 - 先把
alls
排序、去重,然后使用一个方法把alls
数组中所有的数都映射为一个自然数,对应于a
中的第x
位,这个位置中保存的值为这个有效位置里面的数 - 我们对
a
数组使用前缀和算法,得出他的前缀和数组s
- 那么假如我们查询
l...r
区间数的和,映射到a
数组就是L...R
(用大写代表对应的映射值)区间的数的和,结果就是s
数组的s[R] - s[L - 1]
信息保存思路:
那么我们需要记录两种操作产生的有效位置:
- 加法操作:毫无疑问,加法操作让某一个位置变得与众不同,我们需要把他单独记录下来。同时,这个位置增加了多少也是一个关键的信息值得记录。
- 记录:变动位置 + 增加的值
- 查询操作:在“数组处理思路”的第四步里我们发现,最后其实是需要映射查询的两个端点位置的,所以这查询功能中输入的两个数我们也需要存到
alls
中,在后面对其进行映射- 记录:左端点的位置 + 右端点的位置
在实际保存时,我们使用pair
这个数据结构,他的每一个单位里面可以存放两个数据,分别通过.first
和.second
读取
由预备离散化数组转前缀和数组
我们的预备离散化数组为alls
,里面保存了那些特殊的位置
我们的离散化映射数组为a
,是对应于alls
中所有值的存在
我们的前缀和数组为s
,是对a
进行求前缀和操作的结果
alls
中存在两个问题我们需要处理
- 无序:我们在映射的时候应该是一个单调映射,也就是最小的数映射值为0,然后依次映射1,2,3.....
- 处理方法:直接使用
sort
函数
- 处理方法:直接使用
- 有重复的可能:很有可能我们对同一个位置进行了多次加法操作,那么这个位置就会重复存放进
alls
中,或者查询端点重复等- 处理方法:
alls.erase(unique(alls.begin(), alls.end()), alls.end())
unique(alls.begin(), alls.end())
可以将alls
中所有重复的数都移动到数组后面,将重复数的第一次出现的数保留下来。返回值为处理后多余的那一串数组的首位置m
。比如对应一个长度为x
的数组进行处理,返回了m
,那么就说明现在这个数组0...m-1
中是没有重复的数的,重复多余的那些都在m...x-1
处erase(m , alls.end())
我们书接上回unique
返回了m
,现在我们就通过erase
把那多余的一段m....x-1
删除。最后数组就只有不重复的那一串了
- 处理方法:
然后运用自定义函数find
遍历alls
,给所有位置找一个映射值
最后对a
做前缀和处理得出数组s
离散化处理
前排提醒:由于后面要使用前缀和,而前缀和需要把第0位空出来,所以这里我们的映射是从1开始的
其实从alls
映射到a
很简单,已经排好序去完重了,那么alls
第x
位上的位置值m
就能直接对应a
的第x
位。也就是原来无限长数组的位置m
映射为x
。
这里我们使用了二分算法函数find
,其实为了能快速找到输入值m
在alls
数组中的第几位,因为查找的时候并不会告诉你。
数组开多大
这个我们可以从题目中的得知
n
和m
的范围都是1e5
n
是加法,一步加法的两个信息中有一个是位置
m
是查询,一步查询的两个信息都是位置
所以最多(n
,m
拉满,而且他们产生的有效位置无一重复)为n + 2m
也就是300000,我们为了防止数组越界再加个10,最后就是300010
代码
结语
这个算法我多少有点模糊,我总感觉alls
与a
属于并行,他们组合起来作为了原来无限长数组的映射,映射里面包括位置值和数值。
离散化里面其实只映射了位置值
我那个思想好像是往哈希表那边想了?但我没学过,等学过了再看看,我总感觉起码对于这道题,我认为我的那个思路也挺好,刚好可以用pair
把并行的两个数组合并了,因为alls
映射到a
的方法太简单了
__EOF__

本文链接:https://www.cnblogs.com/zaughtercode/p/17229494.html
关于博主:qq:1730119093 欢迎加我讨论
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】