排序算法: 数据的离散化(排序+去重 C++例题实现)

news/2025/1/25 12:07:27/

文章目录

  • 数据的离散化
    • 例题:电影
    • 完整代码

数据的离散化

离散化是指将一个无穷大的集合中的若干个元素映射到一个有限的集合中,以便于对那个无穷大的集合进行操作。

在很多情况下:对于一个规定在Z范围内的整数范围,他有可能包含非常多的重复的元素,真正不同的元素仅有M个,因此我们考虑把这Z个元素进行映射到只包含M个元素的集合中,即与 【1-M】个整数建立映射关系。因此如果一个算法的时间空间复杂度与Z有关,则会降低到与M有关,对于某些重复元素非常多的集合,将会大大提高算法的复杂度


那么显而易见:离散化的首要目的便是给包含Z个元素的集合去重,使得它不包含任意的重复元素,每个元素只出现一次,然后映射到另一个无任何重复元素的集合中,这个集合只包含M个元素。

  1. 我们把a集合中的某一个元素a[i]映射到b[j]中,b[j]中不含任意重复的元素,相当于是排序+去重后得a集合(可以使用STL的unique实现这个功能)
  2. 我们想要得知 j 这个序号表示的是哪一个a集合中的元素,即表示哪一个a[i],只需要返回b[j]即可
  3. 我们想要得知 a[i]这个元素,在b集合中被哪一个序号i所表示,我们就可以使用二分查找来找到它的位置。
int a[11] = { 0,1,1,2,3,4,5,6,9,2,7 };	//注意下标从1开始,a[0]是凑数的
int b[11], m = 0;
void discrete()
{//排序,去重,实现离散化sort(a+1,a+1+10);for (int i=1;i<=n;i++){	if (i==1 || a[i]!=a[i-1]){b[++m]=a[i];}}
}
int find(int x)
{return lower_bound(b+1,b+1+m,x)-b;
}

举例:

int main()
{discrete();cout << b[8] << endl;		//查询i=8(1<=i<=m)代替的是哪一个数值:直接返回b[i]cout << query(5) << endl;   //查询a[j]的值被哪个i替代,只需要二分查找a[j]即可return 0;
}

在这里插入图片描述


例题:电影

AcWing 103 电影

这是一道利用了离散化数据的例题。

可以看到此题中关于语言这一个量的限制达到了10^9 ,并且对于这个语言,我们貌似还必须要用一个数组存储起来,否则就无法操作,因此我们的数组就会存储一个非常大的集合,并且我们的数组还不一定能装下,因此我们考虑使用离散化

做法:

  1. 首先收集所有的语言:使用ori数组。
  2. 然后对于ori数组进行离散化处理,保存离散化数据到uni中。
  3. 根据离散化的数据集合得到每一位科学家懂得的语言编号,保存在ans数组中。
  4. 遍历所有电影,对于每一个电影,分别求出能够使科学家达到很开心的科学家的人数,其次求出达到比较开心的人数,然后对于这两个数据和以前的值取一个最大的值,记录电影编号。

首先收集所有语言:全部存在ori数组里,数组的下标使用tot记录

 cin >> n;  //n:n位科学家  for (int i = 1; i <= n; i++){//科学家懂得的语言编号cin >> p[i];ori[++tot] = p[i];    //原始数据全部存在ori中}cin >> m; //m:m个电影for (int i = 1; i <= m; i++){//每一部电影的语音语言cin >> y[i];ori[++tot] = y[i];}for (int i = 1; i <= m; i++){//每一部电影的字幕语言cin >> z[i];ori[++tot] = z[i];}

然后进行离散化数据!!!!!!!!!!

把离散化数据存放在uni数组中

//排序
sort(ori + 1, ori + 1 + tot);//离散化数据for (int i = 1; i <= tot; i++){if (i == 1 || ori[i] != ori[i - 1]){uni[++k] = ori[i];}}

注意:离散化的数据集合uni中只包含了所有的语言编号,并不包含任何其他数据,如人数等等,统计各个人数是在下一步进行的


统计懂得每种语言的科学家分别有多少人???

使用find进行查询:给出p[i]表示的是未离散化的大集合,要找到这个p[i]在离散化后被哪个编号i所映射,使用find函数。 得到的是一个映射标号i,然后ans[i]表示的是懂得第i种语言的人数。

for (int i = 1; i <= n; i++){//查询懂得某种语言的人数有多少ans[find(p[i])]++;}

统计电影的语音和字幕的人数

同理:

  • ans[find(y[i])]:表示懂得第i部电影的语音的人数,因为在上一步我们已经预处理了懂得每种语言的人数,所有说把一个语言编号i传递给ans,得到的就是懂得 i语言的人数。
  • ans[find(x[i])]:懂得第i部电影的字幕的人数。

统计完成后,如果这一部电影的resy(懂得语音的人数)比上一部电影的resy多(注意:上一部电影的语音用res1保存,上一部的字幕用res2保存),那么更新电影编号;
如果相等,那么再比较字幕。。。

for (int i = 1; i <= m; i++)
{resy = ans[find(y[i])];//懂得语音的人数resz = ans[find(z[i])];//懂得字幕的人数if (resy > res1 || (resy == res1 && resz > res2)){res = i;  //记录电影编号res1 = resy;//记录这部电影的懂得语音的人数res2 = resz;//记录这部电影的懂得字幕的人数}
}

最后答案有可能会出现 没有一个人懂得某部电影的语音和字幕,则随便输出一个。

完整代码

!!!!!!!!!! 注意理解这些变量的名字,不要弄混了!!!!!!!!!!!

#include <bits/stdc++.h>
using namespace std;/*
请你帮忙选择一部电影,可以让观影很开心的人最多。
如果有多部电影满足条件,则在这些电影中挑选观影比较开心的人最多的那一部。
*/
const int N = 200005;
int n, m, resy, resz, res, res1, res2, k = 0, tot = 0;
int p[N], y[N], z[N], ans[3 * N];
int ori[N * 3], uni[3 * N]; //ori存放原始数据,uni存放离散数据  多给点空间
int find(int x)
{//根据a[j]查询替代此a[j]值的序号jreturn lower_bound(uni + 1, uni + 1 + k, x) - uni;
}
int main()
{cin >> n;  //n:n位科学家  for (int i = 1; i <= n; i++){//科学家懂得的语言编号cin >> p[i];ori[++tot] = p[i];    //原始数据全部存在ori中}cin >> m; //m:m个电影for (int i = 1; i <= m; i++){//每一部电影的语音语言cin >> y[i];ori[++tot] = y[i];}for (int i = 1; i <= m; i++){//每一部电影的字幕语言cin >> z[i];ori[++tot] = z[i];}//排序sort(ori + 1, ori + 1 + tot);//离散化数据for (int i = 1; i <= tot; i++){if (i == 1 || ori[i] != ori[i - 1]){uni[++k] = ori[i];}}for (int i = 1; i <= n; i++){//查询懂得某种语言的人数有多少ans[find(p[i])]++;}for (int i = 1; i <= m; i++){resy = ans[find(y[i])];//懂得语音的人数resz = ans[find(z[i])];//懂得字幕的人数if (resy > res1 || (resy == res1 && resz > res2)){res = i;  //记录电影编号res1 = resy;//记录这部电影的懂得语音的人数res2 = resz;//记录这部电影的懂得字幕的人数}}if (res == 0){cout << 1;}else{cout << res;}return 0;
}

参考:
《算法竞赛进阶指南》
AcWing 103 题解


http://www.ppmy.cn/news/19237.html

相关文章

三、利用迁移学习进行模型微调(Datawhale组队学习)

文章目录安装配置环境准备图像分类数据集迁移学习微调训练图像分类模型导入环境图像预处理载入图像分类数据集建立类别和索引号之间映射关系定义数据加载器查看一个batch的图像和标注可视化一个batch的图像和标注模型的构建与测试可视化常见的迁移学习训练方式训练配置模型训练…

梯度之上:Hessian 矩阵

原文链接&#xff1a;原文 文章目录梯度之上&#xff1a;Hessian 矩阵梯度、雅克比矩阵海森矩阵海森矩阵应用梯度之上&#xff1a;Hessian 矩阵 本文讨论研究梯度下降法的一个有力的数学工具&#xff1a;海森矩阵。在讨论海森矩阵之前&#xff0c;需要首先了解梯度和雅克比矩阵…

《c++ primer》第五章 语句

前言 建议看书的时候就看一下异常&#xff0c;其它的直接跳过 一、简单语句 ​ 一条表达式语句以;结尾&#xff0c;它的作用是执行表达式并丢弃掉求值结果。一行如果只有一个;也是一条语句&#xff0c;称为空语句。复合语句时用{}括起来的语句或者声明&#xff0c; 也称为块&a…

分享139个ASP源码,总有一款适合您

ASP源码 分享139个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 139个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1Vk4U4EXVCWZWPMWf9ax2dw?pwdif23 提取码&#x…

Knowledge-based-BERT(一)

多种预训练任务解决NLP处理SMILES的多种弊端&#xff0c;代码&#xff1a;Knowledge-based-BERT&#xff0c;原文&#xff1a;Knowledge-based BERT: a method to extract molecular features like computational chemists&#xff0c;代码解析从K_BERT_pretrain开始。模型框架…

NEZUKO: 1——202201152003

NEZUKO: 1——202201152003 About Release Back to the Top Name: nezuko: 1Date release: 21 Aug 2019Author: yunaranyancatSeries: nezuko Download Back to the Top Please remember that VulnHub is a free community resource so we are unable to check the machin…

基于STM32的FreeRTOS开发(1)----FreeRTOS简介

为什么使用freertos FreeRTOS 是一个免费和开源的实时操作系统&#xff0c;它主要用于嵌入式系统。它非常轻量级&#xff0c;可以在很小的硬件资源上运行&#xff0c;因此非常适合在限制硬件资源的嵌入式系统中使用。 FreeRTOS提供了一组简单的任务管理功能&#xff0c;可以让…

MODBUS总线的学习笔记

MODBUS学习记录 下面所有资料均copy于安富莱电子和博客中&#xff0c;仅作为个人学习笔记记录&#xff0c;写的不好请见谅。 1.modbus简介介绍 Modbus 是由 Modicon&#xff08;现为施耐德电气公司的一个品牌&#xff09;在 1979 年发明的&#xff0c;是全球第一个真正 用于…