数据离散化

题目

问题描述

离散化就是把无限空间(或非常大的空间)中有限的个体映射到有限的空间(较小空间)中去,以此提高算法的时空效率。
通俗的说,离散化就是在不改变数据相对大小的条件下,对数据进行相应的缩小。

栗子

原始数据:
8 999 91 100000 0000 15 999 91 。
离散化后:
1 3 4 2 3 。
离散化有什么用处呢?
有时候我们需要根据数值的大小开一个数组,由于数值很多,没办法开那么大的数组(大了会超内存限制的),但是数据的个数有限。
如:有500000个数字,他们的范围是0-2000000000,这样就满足离散化的条件。我们可以把这些数离散化,最小的缩小为1,大小相邻的依次增加1,这样所有的数的范围一定能缩小到1到500000之间,同时不改变相对大小关系。

任务

给你n个整数序列a[1],a[2],..,a[n]。请你在不改变相对大小关系的前提下进行离散化。

要求

1.离散化后,最小的数值为1。
2.原序列中相同的数,离散后还应相同。
3.大小相邻的两个数离散后相差为1。
4.离散后序列相对位置不变。

输入

第一行
n 原始数据的个数 。
第二行
n 个用一个空格隔开的整数 。

输出

一行
原序列离散后相应的序列 ,相邻两个数之间一个空格隔开。

输入输出样例

discretize.in discretize.out
8 99991 1000000000 15 99991

1 3 4 2 3


数据范围

30%的数据: n<100, 0< a[i]<1000;

100% 的数据: n<500000 0< a[i]<2000000000 

第一种方法

思路

其实就是用一个辅助的数组把你要离散的所有数据存下来。

然后排序,排序是为了后面的二分。

去重,因为我们要保证相同的元素离散化后数字相同。

再用二分把离散化后的数字放回原数组。

注意事项

1.去重并不是把数组中的元素删去,而是重复的部分元素在数组末尾,去重之后数组的大小要减一

2.二分的时候,注意二分的区间范围,一定是离散化后的区间

3.如果需要多个数组同时离散化,那就把这些数组中的数都用数组存下来

核心代码

//n:原数组大小
//num:原数组中的元素
//lsh:离散化的数组
//cnt:离散化后的数组大小 
int lsh[MAXN] , cnt , num[MAXN] , n;
for(int i=1; i<=n; i++)
{
    scanf("%d",&num[i]);
    lsh[i] = num[i];    
}
sort(lsh+1 , lsh+n+1);
cnt = unique(lsh+1 , lsh+n+1) - lsh - 1;
for(int i=1; i<=n; i++)
    num[i] = lower_bound(lsh+1 , lsh+cnt+1 , num[i]) - lsh;

第二种方法

思路

其实就是排序之后,枚举着放回原数组

用一个结构体存下原数和位置,按照原数排序

我结构体里面写了个重载,也可以写一个比较函数

最后离散化后数在rank[]里面

核心代码

struct Node
{
    int data, id;
    bool operator < (const Node& a) const
    {
        return data < a.data;
    }
};
Node num[MAXN];
int rank[MAXN], n;
for (int i = 1; i <= n; i++)
{
    scanf("%d", &num[i].data);
    num[i].id = i;
}
sort(num + 1, num + n + 1);
for (int i = 1; i <= n; i++)
{
    rank[num[i].id] = i;
}

 

posted @ 2020-04-18 15:38  芊枫Thomitics  阅读(568)  评论(0编辑  收藏  举报