算法里面的离散化

news2024/9/23 23:35:23

一、离散化(discretization)在算法和数据结构中指的是将连续的输入数据映射到离散的值或者范围,从而使得处理和计算变得更高效。通常用于处理大范围或者无限可能的输入,以便将其转化为有限的、可以有效处理的范围。

离散化的定义

离散化的主要目的是将连续的值或大范围的值映射到一个有限的集合中,以便进行高效的存储和处理。这通常通过对连续的数据进行排序、分组、或者映射来实现。

离散化的步骤

  1. 排序和编号:对所有唯一的连续值进行排序,然后为这些值分配一个唯一的编号。
  2. 映射:使用一个映射函数,将原始数据的每个值转换为新的编号或索引。

应用场景

  1. 区间压缩:在处理大范围的整数值时,通过离散化可以将这些值映射到一个较小的范围。例如,处理1到10000的值时,可以将它们映射到1到100的范围内。

  2. 数据结构优化:在某些数据结构中(如树状数组或线段树),需要将离散化后的值作为索引来优化查询和更新操作。

离散化在以下方面有应用:

  1. 机器学习:将连续特征转换为离散类别,简化模型处理,例如将年龄分段成“青年”、“中年”、“老年”。
  2. 图像处理:将图像数据的连续像素值转换为离散的色彩级别,提高处理效率。
  3. 数据压缩:将连续信号如音频或视频离散化,以减少存储需求。
  4. 数据库设计:将连续数据映射到离散值,用于更高效的数据索引和查询。

这些应用帮助简化计算、提高效率或改善模型性能。

例子

例子 1:区间压缩

假设有一组连续的坐标值:[100, 150, 300, 600, 900]。我们希望将这些值映射到更小的范围。

  1. 排序和编号

    • 排序后的值:[100, 150, 300, 600, 900]
    • 对这些值进行编号:100 -> 1150 -> 2300 -> 3600 -> 4900 -> 5
  2. 映射

    • 原始值 100 映射到编号 1
    • 原始值 150 映射到编号 2
    • 原始值 300 映射到编号 3
    • 原始值 600 映射到编号 4
    • 原始值 900 映射到编号 5

    这样,我们就将原始的连续值压缩到了 [1, 2, 3, 4, 5],这使得后续的数据结构(如线段树或树状数组)的操作更为高效。

例子 2:二维离散化

假设有一组二维坐标值:[(10, 20), (15, 30), (30, 60)]。我们需要将这些坐标值离散化。

  1. 提取和排序

    • X轴坐标:[10, 15, 30]
    • Y轴坐标:[20, 30, 60]
    • 对X轴坐标编号:10 -> 115 -> 230 -> 3
    • 对Y轴坐标编号:20 -> 130 -> 260 -> 3
  2. 映射

    • (10, 20) 映射到 (1, 1)
    • (15, 30) 映射到 (2, 2)
    • (30, 60) 映射到 (3, 3)

    这样,我们将原始的连续坐标转换成离散的坐标,对数据结构的处理(如二维树状数组)将更加高效。

总结

离散化的关键是将原始的、可能是连续或无限范围的数据,转化为有限且可处理的编号或索引。这样不仅优化了存储空间,也提高了数据处理的效率。

二、在算法中,“映射”是指将一个集合中的每个元素通过某种规则或函数转换为另一个集合中的元素的过程。这一概念广泛应用于数据处理、函数设计和数据结构中。以下是映射的详细解释:

1. 基本定义

映射可以被视为一个函数 ( f: A \rightarrow B ),其中 ( A ) 是定义域,( B ) 是值域。对于定义域中的每个元素 ( a \in A ),映射函数 ( f ) 将其转换为值域中的元素 ( b \in B )。形式上,这可以表示为 ( f(a) = b )。

2. 示例

  • 数学中的映射:一个简单的数学映射是 ( f(x) = x^2 ),它将每个实数 ( x ) 映射到它的平方 ( x^2 )。

  • 数据结构中的映射:在哈希表中,映射是通过哈希函数将键(key)映射到对应的值(value)。例如,键 "name" 可能映射到值 "Alice"。

3. 应用

  • 数据转换:在数据处理过程中,可以将数据从一种格式转换为另一种格式。比如,映射函数可以将用户输入的字符串转换为对应的内部数据结构。

  • 离散化:在离散化过程中,映射用于将连续的数据转换为离散的值。例如,将地理坐标映射到一个有限的网格系统中。

4. 复杂映射

映射不仅限于一对一关系,还可以是多对一(多个输入映射到一个输出)或一对多(一个输入映射到多个输出)。例如,在关系数据库中,某一用户ID可能映射到多个订单记录。

5. 映射的属性

  • 单射(Injective):每个定义域的元素映射到值域中唯一的元素,不存在不同的输入映射到相同的输出。
  • 满射(Surjective):定义域中的每个元素都映射到值域中的某个元素,使得值域中的每个元素至少被映射一次。
  • 双射(Bijective):既是单射又是满射,即每个定义域的元素都有唯一的值域元素,且值域中的每个元素都有唯一的定义域元素。

映射在算法中扮演着重要角色,它使得数据转化、存储和处理变得更加系统化和高效。

了解了什么是离散化和映射,接下来直接开始做题,用题目实践才是最好的。

题目:区间和

假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。

现在,我们首先进行 n次操作,每次操作将某一位置 x上的数加 c。

接下来,进行 m次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r] 之间的所有数的和。

输入格式

第一行包含两个整数 n和 m。

接下来 n 行,每行包含两个整数 x 和 c。

再接下来 m 行,每行包含两个整数 l 和 r。

输出格式

共 m 行,每行输出一个询问中所求的区间内数字和。

数据范围

-10^{9}≤x≤10^{9}
1≤n,m≤10^{5},
-10^{9}≤l≤r≤10^{9},
−10000≤c≤10000

输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5

 

离散化的特点:
值域大,个数少。
可以把这n个数映射到它的下标。
常见的问题:
1. 数组a中有重复元素(去重)
2. 如何算出a_{i}映射后的值?(二分)

此题把下标映射后前缀和求解即可。

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;
typedef pair<int,int> PII;/*定义pair<int,int>类型为PII,就相当于取了一个别名,就是方便使用的时候不输入那么复杂又长的东西。*/
const int N=3e5+10;
/*因为有三个坐标,所以是用的3e5+10的范围。
输入的n个x,m个l,r,就是n+2m个坐标,因为n和m都是10的五次方,所以就是3乘10的5次方,多10是故意开的,害怕越界嘛。*/
int a[N],s[N];
/*这个就是求的区间和,只不过前面还有些步骤,所以这个a[N]数组是存储的值,不是坐标哈;s[N]
还是和前缀和一样,是放的前缀和的值。*/
vector<PII> add,query;
/*观察题目得到,输入的位置x和插入的值c,与后面输入的区间两个边界l,r一样,都是一次输入一对
的数进去,所以这里定义了一个PII类型的vector,来存储要操作的东西。这里面add是存储插入的位置x和值c,而query是查询区间,并求出指定区间的和,所以query存储的是边界l,r的位置*/
vector<int> alls;
/*alls是存储所有的位置的,不管是刚开始的x,还是l,r都存在里面,后面会操作的,很有用处。记住,vector是c++里面的可变数组,所以在进行和数组类似的操作时,也可以像数组那样使用,切记。*/



int find(int x){
    int l=0,r=alls.size()-1;
    while(l<r){
        int mid=l+r>>1;//这里是整数,没有小数,所以可以用位运算。
        if(alls[mid]>=x)  r=mid;//二分的第一个模板,相当于求最小值的那个,不用加1。
        else l=mid+1;
    }
    return r+1;//这里你写l+1也可以,反正最后二分l是约等于r的,都可以。

/**注意返回的是r+1,就是最低是返回1,因为我要求前缀和,所以就这样。/
}
/*这个函数是利用的二分查找,来查找x在alls可变数组里面的位置,也就是x在alls可变数组的数组下标是多少。这其实就是离散化了,alls数组在之前的操作后,已经变得井然有序,每一个输入的坐标值x,l,r在alls里面都有对应的位置,这就已经将原来范围大,数目少且离散,不好处理的坐标给放在了alls数组里面,所以要注意,这个alls数组里面存的是坐标,如果要求对应的值的话,那么就是,例如:要想查询x位置上的值的话,那么就是:1、先找到x这个坐标在alls数组里面的哪个位置,对应的是alls数组的哪个下标。 
 2、找到了以后,就能迅速的在alls数组里面找到x坐标所在的位置。 3、找到位置后就直接能找到x所对应的值了。   这就是离散化:1、vector存输入的位置坐标;2、在这个vector里面找到需要的位置坐标。
3、找到以后就可以像之前那样正常操作了,想查值就查值,想求前缀和就求前缀和。*/


int main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++){
       int x,c; 
       cin>>x>>c;
       add.push_back({x,c});
       alls.push_back(x);
    }
/*输入n,m,并且输入x,c,这x,c是插入所需要的值,所以将这两个值存到add这个vector里面。然后顺便把位置x存入alls这个可变数组里面。*/
    
    for(int i=0;i<m;i++){
        int l,r;
        cin>>l>>r;
        query.push_back({l,r});
        alls.push_back(l);
        alls.push_back(r);
    }
/*输入l,r,并将后面查询求前缀和所需要的值l,r给存入到query这个vector里面去,同时,l,r这两个表示位置的数,也全部存到alls这个可变数组内。*/    

    sort(alls.begin(),alls.end());//排序alls里面的所有坐标值
    alls.erase(unique(alls.begin(),alls.end()),alls.end());//去重并调整里面的坐标值。
/*所有输入的关于位置的数,也就是所谓的坐标,已经排序去重并调整大小了,经过了这两步,得到的是
有序的,且中间没有空位的,新的alls可变数组,这对于后面的离散化是很重要的。*/    


    for(auto item:add){
        int x=find(item.first);//找x这个坐标在alls数组里面的数组下标是多少。
        a[x]+=item.second;//在alls数组里面找到x所在的位置后,就直接执行c的插入操作就可以了。
    }//插入操作
   
    for(int i=1;i<=alls.size();i++)  s[i]=s[i-1]+a[i];//注意i<=alls.size(),是从下标1开始的,不是0.
/*这里还是和求前缀和是一样的,在求前缀和之前都要定义一下前缀和的表示,在我看来就是定义一种性质嘛,注意这里是i从1开始,不从0开始是为了避免边界问题。*/
    
    for(auto item:query){//这个不一定要写成item,随便写自己喜欢的单词就好,不影响的。
        int l=find(item.first),r=find(item.second);//分别求l,r在alls数组里面的位置。
        printf("%d\n",s[r]-s[l-1]);//这就是求前缀和,直接用公式就可以,这是一维前缀和哦。
    }//查询并求前缀和的操作
    
    /*这里面的first,second就是键值,因为我的add和query的vector都是PII类型的,也就是pair<int,int>类型的,就拿这里来说,这里query的item.first指的是输入的l,而item.second指的是输入的r。*/
    return 0;
}

 

 

 上面是y总的分析,我觉得分析的挺好的。

以上就是我对于算法里面的离散化的看法与理解,就这样吧。

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

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

相关文章

opencv之傅里叶变换

文章目录 前言理论基础Numpy实现傅里叶变换实现傅里叶变换实现逆傅里叶变换 高通滤波示例OpenCV实现傅里叶变换实现傅里叶变换实现逆傅里叶变换 低通滤波示例 前言 图像处理一般分为空间域处理和频率域处理。 空间域处理是直接对图像内的像素进行处理。空间域处理主要划分为灰…

Mysql基础练习题 1757.可回收且低脂的产品(力扣)

编写解决方案找出既是低脂又是可回收的产品编号。 题目链接&#xff1a; https://leetcode.cn/problems/recyclable-and-low-fat-products/description/ 建表插入数据&#xff1a; Create table If Not Exists Products (product_id int, low_fats ENUM(Y, N), recyclable …

Kernel 内核 BUG_ON()和WARN_ON()

WARN_ON() DEBUG_ON() 不是一个标准的 Linux 内核宏&#xff0c;它可能是特定内核版本或者特定内核配置中的一个宏&#xff0c;或者在某些内核代码中自定义的宏。一般来说&#xff0c;如果存在 DEBUG_ON()&#xff0c;它可能被用作一个调试开关&#xff0c;用于在调试版本中启…

2024.9.11

时钟 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent> #include <QTimer> #include <QPainter> #include <QPen> #include <QBrush> #include <QTime> #include <QDebug> QT_BEGIN_NA…

国内如何优雅的用Google?无需安装任何工具!

前言 Google可以说时每个程序猿的标配&#xff0c;但由于网络问题&#xff0c;在访问Google的时候或多或少都会遇到一系列的问题&#xff0c;接下来介绍一个非常“炸裂”的Google打开方式。 LiteIcoding 在此之前&#xff0c;你需要访问这个地址 https://lite.icoding.ink 这…

【Qt】QSS的设置方式

QSS的设置方式 QWidget 中包含了 setStyleSheet ⽅法, 可以直接设置样式. 上述代码我们已经演⽰了上述设置⽅式 还可以通过 QApplication 的 setStyleSheet ⽅法设置整个程序的全局样式. 设置全局样式&#xff0c;可以将界面上所有的样式都集中到一起来组织。 全局样式优点:…

56 - II. 数组中数字出现的次数 II

comments: true difficulty: 中等 edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9856%20-%20II.%20%E6%95%B0%E7%BB%84%E4%B8%AD%E6%95%B0%E5%AD%97%E5%87%BA%E7%8E%B0%E7%9A%84%E6%AC%A1%E6%95%B0%20II/README.md 面试题 56 - II. 数…

大屏可视化常用图标效果表达

1-echarts-雷达图 2-echarts-仪表盘 3-echarts-水球图&#xff08;利用插件&#xff0c;echarts-liquidfill&#xff09; 4-element UI tree 添加连接线&#xff0c;修改样式或使用插件&#xff08;element-tree-line&#xff09; 5-echarts-漏斗图 6-echarts-饼状图嵌套 optio…

力扣刷题之2181.合并零之间的节点

题干描述 给你一个链表的头节点 head &#xff0c;该链表包含由 0 分隔开的一连串整数。链表的 开端 和 末尾 的节点都满足 Node.val 0 。 对于每两个相邻的 0 &#xff0c;请你将它们之间的所有节点合并成一个节点&#xff0c;其值是所有已合并节点的值之和。然后将所有 0 …

为什么 1T 的硬盘容量只有 931G?真相在这里!

硬盘容量疑问 以一个容量为 1T 的硬盘为例&#xff0c;在 Windows 系统下&#xff0c;容量显示只有 931G&#xff0c;不应该是 1024GB 吗&#xff1f;这到底是为什么呢&#xff1f;是商家在欺骗消费者吗&#xff1f; 按照之前内存大小的计算逻辑&#xff08;1MB 1024KB&…

AI电商,如何提高设计效率?

第一步&#xff1a;找参考 第二步&#xff1a;提取关键词 我用的文心一言 第三步&#xff1a;选择AI绘画工具&#xff08;千鹿 设计助手&#xff09; 千鹿设计助手——FLux文生图&#xff0c;你也可以选择你手上的AI绘画工具 这个新用户注册会赠送1000积分 第四步生图

[笔记] 电机工作制以及软硬特性的本质推导

原始资料来源&#xff1a;某电机厂商 1.电机非常规操作术语和许可次数 1.1 电机操作术语 点动&#xff1a;通电后立即关停&#xff0c;最终速度不到额定转速的1/4电制动&#xff1a;制动到额定转速的1/3逆转&#xff1a;也就是打反车&#xff0c;不等停车&#xff0c;立即翻…

Java、python、php三个版本 抗震救灾物资管理系统 抗洪救灾物资分配系统 救援物资申请平台(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

在 Web 中判断页面是不是刷新

在 Web 开发中&#xff0c;我们经常需要区分用户是否通过刷新操作重新加载了页面。这一操作可能是由用户手动刷新&#xff08;如按下 F5 键或点击浏览器刷新按钮&#xff09;或通过浏览器自动重新加载。判断页面是否刷新有助于开发者优化用户体验&#xff0c;例如在使用 vue 的…

超详细,手把手带你源码启动 Thingsboard-Gateway + MQTT 接入设备

超详细&#xff0c;手把手带你源码启动 Thingsboard-Gateway MQTT 接入设备 前置条件 thingsboard&#xff0c;我这里选择的是本地源码启动postgresql&#xff0c;这里采用的是个人服务器部署的公共服务EMQX&#xff0c;这里同样采用服务器部署的公共服务MQTTX 客户端Mysql【…

Fiddle的使用------一个非常好用且正规的抓包工具

Fiddle的下载安装&#xff08;看完再去下载安装&#xff09; https://www.telerik.com/download/fiddler 1.点击连接&#xff0c;在表格填上数据&#xff0c;点击下载&#xff0c;下载结束了就安装&#xff0c;一路next就可以了。 2.修改一下设置 以上跟我一样设置&#xff…

Unity 是否能和黑神话悟空一样,接入Nivida的DLSS,用NSight Graphics实际测试

NSight作为Nivida 显卡的调试工具&#xff0c;因为国内都是手游开发盛行的年代&#xff0c;远没有RenderDoc或者高通的QuatXXX 出名 选择NSight的原因很简单&#xff1a; Nividia 财大气粗&#xff0c;倒不是主因&#xff0c; 因为其CEO爱出名&#xff0c;所以手下的人只…

视觉SLAM ch5——相机与图像

一、单目模型 前言&#xff1a;本大标题下1~4部分讲述的都是单目针孔相机 SLAM的数学本质可以抽象为运动方程&#xff08;x&#xff09;和观测方程&#xff08;z&#xff09;&#xff08;书上的第二部分&#xff09; 教材第二章截图 书中P24页截图 其中的未知量为xk&#xff…

828华为云征文|几分钟,即可在华为云Flexus X服务器部署安全稳定的——水果生鲜商城配送小程序

最近由于公司需要开发一个水果生鲜同城配送的小程序&#xff0c;源码代码已经有了&#xff0c;相对于应的功能也开发的七七八八了&#xff0c;随着生鲜商城小程序的相对于应的功能开发逐渐接近尾声。 然而&#xff0c;在这个关键时刻&#xff0c;一个至关重要的决定摆在了团队面…

javase复习day22泛型、set、数据结构

泛型 package MyGenerics;import java.util.ArrayList; import java.util.Iterator;public class GenericsTest1 {public static void main(String[] args) {//没有泛型的情况ArrayList list new ArrayList();//所有数据都被认为是Object类型&#xff0c;都可以加入集合中list…