数据离散化

对应   1331. 数组序号转换

 

 

一、概述

数据离散化是一个非常重要的思想。

现在给出这样的一个问题,有1e5个数,每个数的范围在-1e18至1e18之间,有1e5次询问,每次有一个k,询问第k大的数字出现的次数。

当然,第一想法是用map解决,但是掐指一算复杂度,用map计数以后,对于每一次询问,都需要对map进行一遍遍历,显然复杂度过不去。

这时候我们注意到,对于这个问题,我们要关心的只是数据间的大小关系,而不是具体的数值,所以我们只需要将其一一映射即可。

 

我们来看一下定义:离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。

通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。例如:

对于一组数据3, 100001357, -256, 378, 4, 1,如果将这些数据处理成3, 6, 1, 5, 4, 2,这样的话,直接通过下标索引,就能找到我们要的答案。

样例输入

6
3 100001357 -256 378 4 1

样例输出

3 6 1 5 4 2


二、原理与操作

假如你只想简单操作一下,如求个逆序对什么的,那直接排序后将它的顺序覆盖回去就可以啦。(它不能去重)

假如你想写的更加专业就要采用以下步骤:

1、排序

2、去重

3、索引

首先我们要对所要进行离散化的数据进行排序:一般使用sort对数组或结构体排序。

然后是去重操作,为了写出高效的代码,我们需要复习两个STL函数:unique()和lower_bound(),他们同时隶属于#include<algorithm>。

unique的作用是“去掉”容器中相邻元素的重复元素(不一定要求数组有序),它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址;

函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置。【ps.upper_bound是返回第一个大于b[x]的指针,upper_bound()=lower_bound()+1】

 

代码如下:

class Solution {
public:
    vector<int> arrayRankTransform(vector<int>& arr) {
        vector<int> b = arr;
        sort(b.begin(), b.end());
        b.erase(unique(b.begin(), b.end()), b.end());
        for(auto &x: arr)
            x = upper_bound(b.begin(), b.end(), x) - b.begin();
        return arr;
    }
};

 

当然可以用map 来加速

class Solution:
    def arrayRankTransform(self, arr: List[int]) -> List[int]:
        data = sorted(set(arr))
        mp = dict()
        for i in range(len(data)):
            mp[data[i]] = i+1

        return [mp[i] for i in arr]

 

 
posted @ 2022-07-28 19:38  r1-12king  阅读(49)  评论(0编辑  收藏  举报